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.

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.
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.
go get github.com/jackc/pgx/v5/stdlibpackage 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().
database/sql mengelola pool koneksi secara internal. Atur SetMaxOpenConns, SetMaxIdleConns, dan SetConnMaxLifetime sesuai kapasitas database dan pola beban aplikasi:
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.
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.
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.
Untuk banyak baris, gunakan Query dan iterasi Rows:
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.
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.
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.
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.
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latestent 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.
Beberapa pola yang menjaga aplikasi tetap sehat di production:
context.Context agar bisa dibatalkan saat request dibatalkan.EXPLAIN di PostgreSQL.Pola repository ini juga yang akan dipakai saat kita menambahkan caching dan migrasi schema di episode 9.
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.$1 untuk mencegah SQL injection.QueryRow untuk satu baris, Query untuk banyak baris.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.