Belajar Golang - Database, Persistence, dan Data Access
Episode 8 of 19

Belajar Golang - Database, Persistence, dan Data Access

Episode ini menghubungkan aplikasi Go dengan database: koneksi database/sql dan driver populer, connection pool, query parameterization, dan transaction management. Kalian juga mengenal ORM ringan seperti sqlc, ent, dan gorm.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi yang hanya menyimpan data di memori akan kehilangan semuanya saat restart. Di sinilah persistence berperan. Episode 8 membawa kalian menghubungkan aplikasi Go dengan database relational secara aman dan efisien.

Kita mulai dari database/sql — interface standar Go untuk database SQL — lalu ke driver populer seperti PostgreSQL, connection pool, parameterized query untuk keamanan terhadap SQL injection, dan transaction management untuk konsistensi data. Terakhir, kalian akan melihat perbandingan pendekatan code-generation dengan sqlc, ent, dan gorm.

database/sql dan Driver

Membuka Koneksi

Go tidak membawa driver database bawaan; database/sql adalah interface, dan driver menyediakan implementasinya. Contoh paling populer untuk PostgreSQL adalah github.com/jackc/pgx atau github.com/lib/pq.

Menambah driver PostgreSQL
go get github.com/jackc/pgx/v5/stdlib
Membuka koneksi
package main
 
import (
	"database/sql"
	"fmt"
 
	_ "github.com/jackc/pgx/v5/stdlib"
)
 
func main() {
	dsn := "postgres://user:pass@localhost:5432/app"
	db, err := sql.Open("pgx", dsn)
	if err != nil {
		panic(err)
	}
	defer db.Close()
	fmt.Println("koneksi database siap")
}

Import blank _ "github.com/jackc/pgx/v5/stdlib" menjalankan registrasi driver tanpa memakai identifier-nya. sql.Open tidak langsung menghubungi database; verifikasi dilakukan dengan db.Ping().

Connection Pool

database/sql mengelola pool koneksi secara internal. Atur SetMaxOpenConns, SetMaxIdleConns, dan SetConnMaxLifetime sesuai kapasitas database dan pola beban aplikasi:

Konfigurasi pool
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(30 * time.Minute)

Terlalu banyak koneksi terbuka membuat database kehabisan resource; terlalu sedikit membuat request mengantre. SetConnMaxLifetime mencegah koneksi basi yang bisa memutus di belakang proxy dan load balancer.

Query Parameterization

Menghindari SQL Injection

Aturan paling penting: jangan pernah menyusun query dengan string concatenation. Gunakan placeholder $1, $2 pada PostgreSQL dan ? pada MySQL. Driver meng-escape nilai dengan aman.

Query aman dengan parameter
var nama string
err := db.QueryRow(
	"SELECT nama FROM pengguna WHERE id = $1",
	id,
).Scan(&nama)
if err != nil {
	log.Fatal(err)
}
fmt.Println("nama:", nama)

QueryRow mengembalikan satu baris dan Scan memetakan kolom ke variabel. Jika query tidak menghasilkan baris, error sql.ErrNoRows dikembalikan — periksa dan beri respons yang tepat. Contoh ini adalah bagian dari pattern yang bisa diuji cepat dengan go run main.go setelah koneksi database tersedia.

SELECT dengan Banyak Baris

Untuk banyak baris, gunakan Query dan iterasi Rows:

Query banyak baris
rows, err := db.Query(
	"SELECT id, nama FROM pengguna WHERE aktif = $1",
	true,
)
if err != nil {
	log.Fatal(err)
}
defer rows.Close()
 
for rows.Next() {
	var id int
	var nama string
	if err := rows.Scan(&id, &nama); err != nil {
		log.Fatal(err)
	}
	fmt.Println(id, nama)
}
if err := rows.Err(); err != nil {
	log.Fatal(err)
}

rows.Close() dan rows.Err() wajib dipanggil untuk melepaskan koneksi dan memeriksa error yang muncul selama iterasi.

Transaction Management

BEGIN, COMMIT, dan ROLLBACK

Operasi yang melibatkan beberapa query harus berjalan dalam satu transaksi agar konsisten — misalnya transfer antar rekening. db.BeginTx memulai transaksi, tx.Commit mengunci hasil, dan tx.Rollback membatalkan.

Transaksi transfer
tx, err := db.BeginTx(ctx, nil)
if err != nil {
	return err
}
defer tx.Rollback()
 
_, err = tx.Exec(
	"UPDATE rekening SET saldo = saldo - $1 WHERE id = $2",
	jumlah, dariRekening,
)
if err != nil {
	return err
}
_, err = tx.Exec(
	"UPDATE rekening SET saldo = saldo + $1 WHERE id = $2",
	jumlah, keRekening,
)
if err != nil {
	return err
}
 
return tx.Commit()

defer tx.Rollback() aman dipanggil bahkan setelah Commit — setelah commit, rollback menjadi no-op. Semua query yang memakai tx akan berbagi transaksi yang sama.

ORM dan Code Generation

sqlc: SQL Sebagai Sumber Kebenaran

sqlc membangkitkan kode Go dari file SQL. Kalian menulis query sebagai SQL murni, dan sqlc menghasilkan fungsi typed-safe yang bebas refleksi. Pendekatan ini menjaga kontrol penuh atas query.

Install sqlc
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest

ent dan gorm

ent adalah framework entity dengan code generation, populer untuk schema yang kompleks dan bergraf. gorm adalah ORM yang menawarkan mapping struct-ke-tabel dengan migrasi otomatis. Pilihannya: gunakan sqlc untuk query yang perlu dikontrol, ent untuk domain model yang besar, dan gorm untuk prototipe cepat. Konsistensi performa dan kemudahan debugging adalah pertimbangan utama.

Best Practice Data Access

Beberapa pola yang menjaga aplikasi tetap sehat di production:

  • Parameterized query untuk semua input pengguna.
  • Context-aware: operasi database memakai context.Context agar bisa dibatalkan saat request dibatalkan.
  • Repository pattern: pisahkan query dari logika bisnis agar mudah diuji dengan mock.
  • Index yang tepat: profile query lambat dengan EXPLAIN di PostgreSQL.
  • Rate limit database: hindari ledakan koneksi saat beban puncak.

Pola repository ini juga yang akan dipakai saat kita menambahkan caching dan migrasi schema di episode 9.

Penutup

Episode 8 menghubungkan aplikasi Go dengan dunia database: membuka koneksi dengan database/sql dan driver pgx, mengatur connection pool, menulis parameterized query yang aman dari SQL injection, mengelola transaksi dengan BeginTx, Commit, dan Rollback, serta memilih antara sqlc, ent, dan gorm.

Inti yang harus dibawa pulang:

  • database/sql adalah interface; driver menyediakan implementasi.
  • Atur pool koneksi agar database tidak kewalahan.
  • Selalu pakai placeholder $1 untuk mencegah SQL injection.
  • QueryRow untuk satu baris, Query untuk banyak baris.
  • Gunakan transaksi untuk operasi multi-query yang konsisten.
  • sqlc untuk kontrol penuh, ent atau gorm untuk produktivitas.

Di episode 9 selanjutnya kita akan membahas state, caching, dan schema migrations — teknik caching in-memory dan integrasi Redis dengan go-redis, manajemen schema database dengan golang-migrate, serta strategi state management untuk service Go. Aplikasi kalian akan lebih cepat dan strukturnya lebih terkelola.

Belajar Golang - Database, Persistence, dan Data Access | Belajar Golang