Go database/sql Dasar
Definisi
database/sql adalah package standar Go untuk akses database relational secara generik. Ia tidak menyediakan driver sendiri; kamu impor driver (misal github.com/lib/pq, github.com/go-sql-driver/mysql) sekadar untuk side-effect, lalu pakai sql.DB sebagai abstraksi connection pool.
Kapan dipakai
Pakai database/sql untuk operasi SQL biasa (CRUD, transaksi) tanpa ORM. Cocok saat butuh kontrol penuh atas query, index, dan pool. Hindari kalau butuh migrasi otomatis tingkat tinggi; kombinasikan dengan tool migrasi terpisah.
Cara kerja
Buka koneksi
import (
"database/sql"
_ "github.com/lib/pq" // driver Postgres, impor untuk efek samping
)
db, err := sql.Open("postgres", "postgres://user:pass@localhost/db?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()sql.Open tidak langsung connect; panggil db.Ping() untuk memastikan.
Query baris tunggal
var name string
err := db.QueryRow("SELECT name FROM users WHERE id = $1", 1).Scan(&name)
if err != nil {
if err == sql.ErrNoRows {
// tidak ketemu
}
}Query banyak baris
rows, err := db.Query("SELECT id, name FROM users")
if err != nil { return err }
defer rows.Close()
for rows.Next() {
var id int
var name string
if err := rows.Scan(&id, &name); err != nil {
return err
}
}
return rows.Err() // cek error setelah loopPrepared statement
stmt, err := db.Prepare("INSERT INTO users(name) VALUES($1) RETURNING id")
if err != nil { return err }
defer stmt.Close()
var id int
stmt.QueryRow("Budi").Scan(&id)Transaksi
tx, err := db.Begin()
if err != nil { return err }
defer tx.Rollback() // aman dipanggil meski sudah Commit
_, err = tx.Exec("UPDATE accounts SET balance = balance - $1 WHERE id=$2", 100, 1)
if err != nil { return err }
if err = tx.Commit(); err != nil { return err }Struktur alur
Loading diagram...
Catatan implementasi
sql.DBadalah pool, bukan koneksi tunggal; janganClosetiap request, cukup sekali di lifecycle app.- Set
db.SetMaxOpenConns,SetMaxIdleConns,SetConnMaxLifetimesesuai beban. - Selalu
defer rows.Close()dan cekrows.Err()setelah loop. - Gunakan
?untuk MySQL,$1 $2untuk Postgres (tergantung driver). ctxversi (QueryContext,ExecContext) wajib untuk timeout/cancel yang benar.
Kesalahan umum
- Lupa
rows.Close(): koneksi bocor, pool habis saat traffic tinggi. - Tidak cek
rows.Err(): error di tengah loop terlewat. OpentanpaPing: error koneksi baru muncul saat query pertama, sulit debug.- Prepare di dalam loop: overhead; prepare sekali di luar loop.
- Tx lupa Commit: perubahan tidak tersimpan, padahal tidak error.