Skip to content

Go Database Patterns Best Practices

Objective: Master senior-level Go database patterns for production systems. When you need to build robust, scalable database applications, when you want to optimize database performance, when you need enterprise-grade database patternsโ€”these best practices become your weapon of choice.

Core Principles

  • Connection Pooling: Efficiently manage database connections
  • Transaction Management: Ensure data consistency and integrity
  • Query Optimization: Write efficient and maintainable queries
  • Error Handling: Handle database errors gracefully
  • Migration Management: Version and manage database schema changes

Connection Pooling

Database Connection Pool

// internal/database/connection_pool.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "sync"
    "time"
)

// ConnectionPool represents a database connection pool
type ConnectionPool struct {
    db     *sql.DB
    config PoolConfig
    mutex  sync.RWMutex
    stats  PoolStats
}

// PoolConfig represents connection pool configuration
type PoolConfig struct {
    MaxOpenConns    int           `json:"max_open_conns"`
    MaxIdleConns    int           `json:"max_idle_conns"`
    ConnMaxLifetime time.Duration `json:"conn_max_lifetime"`
    ConnMaxIdleTime time.Duration `json:"conn_max_idle_time"`
    PingInterval    time.Duration `json:"ping_interval"`
}

// PoolStats represents connection pool statistics
type PoolStats struct {
    OpenConnections     int           `json:"open_connections"`
    InUse              int           `json:"in_use"`
    Idle               int           `json:"idle"`
    WaitCount          int64         `json:"wait_count"`
    WaitDuration       time.Duration `json:"wait_duration"`
    MaxIdleClosed      int64         `json:"max_idle_closed"`
    MaxIdleTimeClosed  int64         `json:"max_idle_time_closed"`
    MaxLifetimeClosed  int64         `json:"max_lifetime_closed"`
}

// NewConnectionPool creates a new connection pool
func NewConnectionPool(driver, dsn string, config PoolConfig) (*ConnectionPool, error) {
    db, err := sql.Open(driver, dsn)
    if err != nil {
        return nil, fmt.Errorf("failed to open database: %w", err)
    }

    // Configure connection pool
    db.SetMaxOpenConns(config.MaxOpenConns)
    db.SetMaxIdleConns(config.MaxIdleConns)
    db.SetConnMaxLifetime(config.ConnMaxLifetime)
    db.SetConnMaxIdleTime(config.ConnMaxIdleTime)

    pool := &ConnectionPool{
        db:     db,
        config: config,
    }

    // Start health monitoring
    go pool.monitorHealth()

    return pool, nil
}

// GetDB returns the database connection
func (cp *ConnectionPool) GetDB() *sql.DB {
    return cp.db
}

// Ping pings the database
func (cp *ConnectionPool) Ping(ctx context.Context) error {
    return cp.db.PingContext(ctx)
}

// Close closes the connection pool
func (cp *ConnectionPool) Close() error {
    return cp.db.Close()
}

// GetStats returns connection pool statistics
func (cp *ConnectionPool) GetStats() PoolStats {
    cp.mutex.RLock()
    defer cp.mutex.RUnlock()

    stats := cp.db.Stats()
    return PoolStats{
        OpenConnections:    stats.OpenConnections,
        InUse:             stats.InUse,
        Idle:              stats.Idle,
        WaitCount:         stats.WaitCount,
        WaitDuration:      stats.WaitDuration,
        MaxIdleClosed:     stats.MaxIdleClosed,
        MaxIdleTimeClosed: stats.MaxIdleTimeClosed,
        MaxLifetimeClosed: stats.MaxLifetimeClosed,
    }
}

// monitorHealth monitors the health of the connection pool
func (cp *ConnectionPool) monitorHealth() {
    ticker := time.NewTicker(cp.config.PingInterval)
    defer ticker.Stop()

    for range ticker.C {
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        if err := cp.db.PingContext(ctx); err != nil {
            // Handle ping failure
        }
        cancel()
    }
}

// Execute executes a query with retry logic
func (cp *ConnectionPool) Execute(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
    var result sql.Result
    var err error

    for i := 0; i < 3; i++ {
        result, err = cp.db.ExecContext(ctx, query, args...)
        if err == nil {
            return result, nil
        }

        if i < 2 {
            time.Sleep(time.Duration(i+1) * time.Second)
        }
    }

    return nil, fmt.Errorf("failed to execute query after 3 attempts: %w", err)
}

// Query executes a query and returns rows
func (cp *ConnectionPool) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
    return cp.db.QueryContext(ctx, query, args...)
}

// QueryRow executes a query and returns a single row
func (cp *ConnectionPool) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row {
    return cp.db.QueryRowContext(ctx, query, args...)
}

Prepared Statement Cache

// internal/database/prepared_statements.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "sync"
)

// PreparedStatementCache represents a prepared statement cache
type PreparedStatementCache struct {
    db        *sql.DB
    statements map[string]*sql.Stmt
    mutex     sync.RWMutex
}

// NewPreparedStatementCache creates a new prepared statement cache
func NewPreparedStatementCache(db *sql.DB) *PreparedStatementCache {
    return &PreparedStatementCache{
        db:         db,
        statements: make(map[string]*sql.Stmt),
    }
}

// Get gets a prepared statement
func (psc *PreparedStatementCache) Get(ctx context.Context, query string) (*sql.Stmt, error) {
    psc.mutex.RLock()
    stmt, exists := psc.statements[query]
    psc.mutex.RUnlock()

    if exists {
        return stmt, nil
    }

    psc.mutex.Lock()
    defer psc.mutex.Unlock()

    // Double-check after acquiring write lock
    if stmt, exists := psc.statements[query]; exists {
        return stmt, nil
    }

    stmt, err := psc.db.PrepareContext(ctx, query)
    if err != nil {
        return nil, fmt.Errorf("failed to prepare statement: %w", err)
    }

    psc.statements[query] = stmt
    return stmt, nil
}

// Execute executes a prepared statement
func (psc *PreparedStatementCache) Execute(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
    stmt, err := psc.Get(ctx, query)
    if err != nil {
        return nil, err
    }

    return stmt.ExecContext(ctx, args...)
}

// Query executes a prepared statement and returns rows
func (psc *PreparedStatementCache) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
    stmt, err := psc.Get(ctx, query)
    if err != nil {
        return nil, err
    }

    return stmt.QueryContext(ctx, args...)
}

// QueryRow executes a prepared statement and returns a single row
func (psc *PreparedStatementCache) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row {
    stmt, err := psc.Get(ctx, query)
    if err != nil {
        return nil, err
    }

    return stmt.QueryRowContext(ctx, args...)
}

// Close closes all prepared statements
func (psc *PreparedStatementCache) Close() error {
    psc.mutex.Lock()
    defer psc.mutex.Unlock()

    for _, stmt := range psc.statements {
        if err := stmt.Close(); err != nil {
            return err
        }
    }

    psc.statements = make(map[string]*sql.Stmt)
    return nil
}

Transaction Management

Transaction Manager

// internal/database/transaction_manager.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "sync"
)

// TransactionManager represents a transaction manager
type TransactionManager struct {
    db *sql.DB
}

// NewTransactionManager creates a new transaction manager
func NewTransactionManager(db *sql.DB) *TransactionManager {
    return &TransactionManager{db: db}
}

// Transaction represents a database transaction
type Transaction struct {
    tx     *sql.Tx
    ctx    context.Context
    mutex  sync.RWMutex
    closed bool
}

// NewTransaction creates a new transaction
func (tm *TransactionManager) NewTransaction(ctx context.Context) (*Transaction, error) {
    tx, err := tm.db.BeginTx(ctx, nil)
    if err != nil {
        return nil, fmt.Errorf("failed to begin transaction: %w", err)
    }

    return &Transaction{
        tx:     tx,
        ctx:    ctx,
        closed: false,
    }, nil
}

// Execute executes a query within the transaction
func (t *Transaction) Execute(query string, args ...interface{}) (sql.Result, error) {
    t.mutex.RLock()
    defer t.mutex.RUnlock()

    if t.closed {
        return nil, fmt.Errorf("transaction is closed")
    }

    return t.tx.ExecContext(t.ctx, query, args...)
}

// Query executes a query within the transaction
func (t *Transaction) Query(query string, args ...interface{}) (*sql.Rows, error) {
    t.mutex.RLock()
    defer t.mutex.RUnlock()

    if t.closed {
        return nil, fmt.Errorf("transaction is closed")
    }

    return t.tx.QueryContext(t.ctx, query, args...)
}

// QueryRow executes a query within the transaction
func (t *Transaction) QueryRow(query string, args ...interface{}) *sql.Row {
    t.mutex.RLock()
    defer t.mutex.RUnlock()

    if t.closed {
        return nil
    }

    return t.tx.QueryRowContext(t.ctx, query, args...)
}

// Commit commits the transaction
func (t *Transaction) Commit() error {
    t.mutex.Lock()
    defer t.mutex.Unlock()

    if t.closed {
        return fmt.Errorf("transaction is already closed")
    }

    err := t.tx.Commit()
    t.closed = true
    return err
}

// Rollback rolls back the transaction
func (t *Transaction) Rollback() error {
    t.mutex.Lock()
    defer t.mutex.Unlock()

    if t.closed {
        return nil
    }

    err := t.tx.Rollback()
    t.closed = true
    return err
}

// WithTransaction executes a function within a transaction
func (tm *TransactionManager) WithTransaction(ctx context.Context, fn func(*Transaction) error) error {
    tx, err := tm.NewTransaction(ctx)
    if err != nil {
        return err
    }

    defer func() {
        if !tx.closed {
            tx.Rollback()
        }
    }()

    if err := fn(tx); err != nil {
        return err
    }

    return tx.Commit()
}

Optimistic Locking

// internal/database/optimistic_locking.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "time"
)

// OptimisticLock represents an optimistic lock
type OptimisticLock struct {
    ID        int64     `json:"id"`
    Version   int64     `json:"version"`
    UpdatedAt time.Time `json:"updated_at"`
}

// OptimisticLocking provides optimistic locking functionality
type OptimisticLocking struct {
    db *sql.DB
}

// NewOptimisticLocking creates a new optimistic locking instance
func NewOptimisticLocking(db *sql.DB) *OptimisticLocking {
    return &OptimisticLocking{db: db}
}

// UpdateWithOptimisticLock updates a record with optimistic locking
func (ol *OptimisticLocking) UpdateWithOptimisticLock(ctx context.Context, table string, id int64, currentVersion int64, updates map[string]interface{}) error {
    // Build update query
    query := fmt.Sprintf("UPDATE %s SET version = version + 1, updated_at = NOW()", table)
    args := []interface{}{}
    argIndex := 1

    for column, value := range updates {
        query += fmt.Sprintf(", %s = $%d", column, argIndex)
        args = append(args, value)
        argIndex++
    }

    query += fmt.Sprintf(" WHERE id = $%d AND version = $%d", argIndex, argIndex+1)
    args = append(args, id, currentVersion)

    result, err := ol.db.ExecContext(ctx, query, args...)
    if err != nil {
        return fmt.Errorf("failed to update record: %w", err)
    }

    rowsAffected, err := result.RowsAffected()
    if err != nil {
        return fmt.Errorf("failed to get rows affected: %w", err)
    }

    if rowsAffected == 0 {
        return fmt.Errorf("record was modified by another process")
    }

    return nil
}

// GetWithOptimisticLock gets a record with optimistic locking
func (ol *OptimisticLocking) GetWithOptimisticLock(ctx context.Context, table string, id int64) (*OptimisticLock, error) {
    query := fmt.Sprintf("SELECT id, version, updated_at FROM %s WHERE id = $1", table)

    var lock OptimisticLock
    err := ol.db.QueryRowContext(ctx, query, id).Scan(
        &lock.ID,
        &lock.Version,
        &lock.UpdatedAt,
    )

    if err != nil {
        if err == sql.ErrNoRows {
            return nil, fmt.Errorf("record not found")
        }
        return nil, fmt.Errorf("failed to get record: %w", err)
    }

    return &lock, nil
}

Query Optimization

Query Builder

// internal/database/query_builder.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "strings"
)

// QueryBuilder represents a query builder
type QueryBuilder struct {
    table     string
    columns   []string
    where     []string
    args      []interface{}
    orderBy   []string
    limit     int
    offset    int
    joins     []string
    groupBy   []string
    having    []string
}

// NewQueryBuilder creates a new query builder
func NewQueryBuilder(table string) *QueryBuilder {
    return &QueryBuilder{
        table:   table,
        columns: []string{"*"},
        where:   make([]string, 0),
        args:    make([]interface{}, 0),
        orderBy: make([]string, 0),
        joins:   make([]string, 0),
        groupBy: make([]string, 0),
        having:  make([]string, 0),
    }
}

// Select sets the columns to select
func (qb *QueryBuilder) Select(columns ...string) *QueryBuilder {
    qb.columns = columns
    return qb
}

// Where adds a WHERE clause
func (qb *QueryBuilder) Where(condition string, args ...interface{}) *QueryBuilder {
    qb.where = append(qb.where, condition)
    qb.args = append(qb.args, args...)
    return qb
}

// Join adds a JOIN clause
func (qb *QueryBuilder) Join(table, condition string) *QueryBuilder {
    qb.joins = append(qb.joins, fmt.Sprintf("JOIN %s ON %s", table, condition))
    return qb
}

// LeftJoin adds a LEFT JOIN clause
func (qb *QueryBuilder) LeftJoin(table, condition string) *QueryBuilder {
    qb.joins = append(qb.joins, fmt.Sprintf("LEFT JOIN %s ON %s", table, condition))
    return qb
}

// OrderBy adds an ORDER BY clause
func (qb *QueryBuilder) OrderBy(column string, direction string) *QueryBuilder {
    qb.orderBy = append(qb.orderBy, fmt.Sprintf("%s %s", column, direction))
    return qb
}

// GroupBy adds a GROUP BY clause
func (qb *QueryBuilder) GroupBy(columns ...string) *QueryBuilder {
    qb.groupBy = append(qb.groupBy, columns...)
    return qb
}

// Having adds a HAVING clause
func (qb *QueryBuilder) Having(condition string, args ...interface{}) *QueryBuilder {
    qb.having = append(qb.having, condition)
    qb.args = append(qb.args, args...)
    return qb
}

// Limit sets the LIMIT
func (qb *QueryBuilder) Limit(limit int) *QueryBuilder {
    qb.limit = limit
    return qb
}

// Offset sets the OFFSET
func (qb *QueryBuilder) Offset(offset int) *QueryBuilder {
    qb.offset = offset
    return qb
}

// Build builds the SELECT query
func (qb *QueryBuilder) Build() (string, []interface{}) {
    query := fmt.Sprintf("SELECT %s FROM %s", strings.Join(qb.columns, ", "), qb.table)

    if len(qb.joins) > 0 {
        query += " " + strings.Join(qb.joins, " ")
    }

    if len(qb.where) > 0 {
        query += " WHERE " + strings.Join(qb.where, " AND ")
    }

    if len(qb.groupBy) > 0 {
        query += " GROUP BY " + strings.Join(qb.groupBy, ", ")
    }

    if len(qb.having) > 0 {
        query += " HAVING " + strings.Join(qb.having, " AND ")
    }

    if len(qb.orderBy) > 0 {
        query += " ORDER BY " + strings.Join(qb.orderBy, ", ")
    }

    if qb.limit > 0 {
        query += fmt.Sprintf(" LIMIT %d", qb.limit)
    }

    if qb.offset > 0 {
        query += fmt.Sprintf(" OFFSET %d", qb.offset)
    }

    return query, qb.args
}

// Execute executes the query
func (qb *QueryBuilder) Execute(ctx context.Context, db *sql.DB) (*sql.Rows, error) {
    query, args := qb.Build()
    return db.QueryContext(ctx, query, args...)
}

// ExecuteRow executes the query and returns a single row
func (qb *QueryBuilder) ExecuteRow(ctx context.Context, db *sql.DB) *sql.Row {
    query, args := qb.Build()
    return db.QueryRowContext(ctx, query, args...)
}

Query Cache

// internal/database/query_cache.go
package database

import (
    "context"
    "crypto/md5"
    "database/sql"
    "encoding/hex"
    "fmt"
    "sync"
    "time"
)

// QueryCache represents a query cache
type QueryCache struct {
    cache    map[string]CacheEntry
    mutex    sync.RWMutex
    ttl      time.Duration
    maxSize  int
}

// CacheEntry represents a cache entry
type CacheEntry struct {
    Data      interface{}
    Timestamp time.Time
    TTL       time.Duration
}

// NewQueryCache creates a new query cache
func NewQueryCache(ttl time.Duration, maxSize int) *QueryCache {
    cache := &QueryCache{
        cache:   make(map[string]CacheEntry),
        ttl:     ttl,
        maxSize: maxSize,
    }

    // Start cleanup goroutine
    go cache.cleanup()

    return cache
}

// Get gets a value from the cache
func (qc *QueryCache) Get(key string) (interface{}, bool) {
    qc.mutex.RLock()
    defer qc.mutex.RUnlock()

    entry, exists := qc.cache[key]
    if !exists {
        return nil, false
    }

    if time.Since(entry.Timestamp) > entry.TTL {
        return nil, false
    }

    return entry.Data, true
}

// Set sets a value in the cache
func (qc *QueryCache) Set(key string, value interface{}, ttl time.Duration) {
    qc.mutex.Lock()
    defer qc.mutex.Unlock()

    // Check if cache is full
    if len(qc.cache) >= qc.maxSize {
        qc.evictOldest()
    }

    qc.cache[key] = CacheEntry{
        Data:      value,
        Timestamp: time.Now(),
        TTL:       ttl,
    }
}

// evictOldest evicts the oldest entry
func (qc *QueryCache) evictOldest() {
    var oldestKey string
    var oldestTime time.Time

    for key, entry := range qc.cache {
        if oldestKey == "" || entry.Timestamp.Before(oldestTime) {
            oldestKey = key
            oldestTime = entry.Timestamp
        }
    }

    if oldestKey != "" {
        delete(qc.cache, oldestKey)
    }
}

// cleanup removes expired entries
func (qc *QueryCache) cleanup() {
    ticker := time.NewTicker(5 * time.Minute)
    defer ticker.Stop()

    for range ticker.C {
        qc.mutex.Lock()
        now := time.Now()
        for key, entry := range qc.cache {
            if now.Sub(entry.Timestamp) > entry.TTL {
                delete(qc.cache, key)
            }
        }
        qc.mutex.Unlock()
    }
}

// CachedQuery executes a cached query
func (qc *QueryCache) CachedQuery(ctx context.Context, db *sql.DB, query string, args ...interface{}) ([]map[string]interface{}, error) {
    // Generate cache key
    key := qc.generateKey(query, args...)

    // Check cache
    if cached, exists := qc.Get(key); exists {
        return cached.([]map[string]interface{}), nil
    }

    // Execute query
    rows, err := db.QueryContext(ctx, query, args...)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    // Convert to map
    result, err := qc.rowsToMap(rows)
    if err != nil {
        return nil, err
    }

    // Cache result
    qc.Set(key, result, qc.ttl)

    return result, nil
}

// generateKey generates a cache key
func (qc *QueryCache) generateKey(query string, args ...interface{}) string {
    data := fmt.Sprintf("%s%v", query, args)
    hash := md5.Sum([]byte(data))
    return hex.EncodeToString(hash[:])
}

// rowsToMap converts rows to map
func (qc *QueryCache) rowsToMap(rows *sql.Rows) ([]map[string]interface{}, error) {
    columns, err := rows.Columns()
    if err != nil {
        return nil, err
    }

    var result []map[string]interface{}

    for rows.Next() {
        values := make([]interface{}, len(columns))
        valuePtrs := make([]interface{}, len(columns))

        for i := range values {
            valuePtrs[i] = &values[i]
        }

        if err := rows.Scan(valuePtrs...); err != nil {
            return nil, err
        }

        row := make(map[string]interface{})
        for i, col := range columns {
            row[col] = values[i]
        }

        result = append(result, row)
    }

    return result, nil
}

Migration Management

Migration Manager

// internal/database/migration_manager.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "sort"
    "time"
)

// Migration represents a database migration
type Migration struct {
    Version     int       `json:"version"`
    Name        string    `json:"name"`
    UpSQL       string    `json:"up_sql"`
    DownSQL     string    `json:"down_sql"`
    CreatedAt   time.Time `json:"created_at"`
    AppliedAt   *time.Time `json:"applied_at,omitempty"`
}

// MigrationManager represents a migration manager
type MigrationManager struct {
    db         *sql.DB
    migrations []Migration
}

// NewMigrationManager creates a new migration manager
func NewMigrationManager(db *sql.DB) *MigrationManager {
    return &MigrationManager{
        db:         db,
        migrations: make([]Migration, 0),
    }
}

// AddMigration adds a migration
func (mm *MigrationManager) AddMigration(migration Migration) {
    mm.migrations = append(mm.migrations, migration)
    sort.Slice(mm.migrations, func(i, j int) bool {
        return mm.migrations[i].Version < mm.migrations[j].Version
    })
}

// Migrate runs all pending migrations
func (mm *MigrationManager) Migrate(ctx context.Context) error {
    // Create migrations table if it doesn't exist
    if err := mm.createMigrationsTable(ctx); err != nil {
        return fmt.Errorf("failed to create migrations table: %w", err)
    }

    // Get applied migrations
    applied, err := mm.getAppliedMigrations(ctx)
    if err != nil {
        return fmt.Errorf("failed to get applied migrations: %w", err)
    }

    // Run pending migrations
    for _, migration := range mm.migrations {
        if _, exists := applied[migration.Version]; !exists {
            if err := mm.runMigration(ctx, migration); err != nil {
                return fmt.Errorf("failed to run migration %d: %w", migration.Version, err)
            }
        }
    }

    return nil
}

// Rollback rolls back the last migration
func (mm *MigrationManager) Rollback(ctx context.Context) error {
    // Get applied migrations
    applied, err := mm.getAppliedMigrations(ctx)
    if err != nil {
        return fmt.Errorf("failed to get applied migrations: %w", err)
    }

    // Find the last applied migration
    var lastMigration *Migration
    for _, migration := range mm.migrations {
        if _, exists := applied[migration.Version]; exists {
            lastMigration = &migration
        }
    }

    if lastMigration == nil {
        return fmt.Errorf("no migrations to rollback")
    }

    // Rollback the migration
    if err := mm.rollbackMigration(ctx, *lastMigration); err != nil {
        return fmt.Errorf("failed to rollback migration %d: %w", lastMigration.Version, err)
    }

    return nil
}

// createMigrationsTable creates the migrations table
func (mm *MigrationManager) createMigrationsTable(ctx context.Context) error {
    query := `
        CREATE TABLE IF NOT EXISTS migrations (
            version INTEGER PRIMARY KEY,
            name VARCHAR(255) NOT NULL,
            applied_at TIMESTAMP NOT NULL DEFAULT NOW()
        )
    `

    _, err := mm.db.ExecContext(ctx, query)
    return err
}

// getAppliedMigrations gets applied migrations
func (mm *MigrationManager) getAppliedMigrations(ctx context.Context) (map[int]bool, error) {
    query := "SELECT version FROM migrations ORDER BY version"
    rows, err := mm.db.QueryContext(ctx, query)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    applied := make(map[int]bool)
    for rows.Next() {
        var version int
        if err := rows.Scan(&version); err != nil {
            return nil, err
        }
        applied[version] = true
    }

    return applied, nil
}

// runMigration runs a migration
func (mm *MigrationManager) runMigration(ctx context.Context, migration Migration) error {
    // Start transaction
    tx, err := mm.db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // Run migration SQL
    if _, err := tx.ExecContext(ctx, migration.UpSQL); err != nil {
        return err
    }

    // Record migration
    query := "INSERT INTO migrations (version, name) VALUES ($1, $2)"
    if _, err := tx.ExecContext(ctx, query, migration.Version, migration.Name); err != nil {
        return err
    }

    // Commit transaction
    return tx.Commit()
}

// rollbackMigration rolls back a migration
func (mm *MigrationManager) rollbackMigration(ctx context.Context, migration Migration) error {
    // Start transaction
    tx, err := mm.db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // Run rollback SQL
    if _, err := tx.ExecContext(ctx, migration.DownSQL); err != nil {
        return err
    }

    // Remove migration record
    query := "DELETE FROM migrations WHERE version = $1"
    if _, err := tx.ExecContext(ctx, query, migration.Version); err != nil {
        return err
    }

    // Commit transaction
    return tx.Commit()
}

ORM Patterns

Simple ORM

// internal/database/orm.go
package database

import (
    "context"
    "database/sql"
    "fmt"
    "reflect"
    "strings"
    "time"
)

// ORM represents a simple ORM
type ORM struct {
    db *sql.DB
}

// NewORM creates a new ORM
func NewORM(db *sql.DB) *ORM {
    return &ORM{db: db}
}

// Model represents a database model
type Model interface {
    TableName() string
    PrimaryKey() string
    Fields() map[string]interface{}
    SetFields(fields map[string]interface{})
}

// User represents a user model
type User struct {
    ID        int64     `json:"id" db:"id"`
    Name      string    `json:"name" db:"name"`
    Email     string    `json:"email" db:"email"`
    CreatedAt time.Time `json:"created_at" db:"created_at"`
    UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

// TableName returns the table name
func (u *User) TableName() string {
    return "users"
}

// PrimaryKey returns the primary key field
func (u *User) PrimaryKey() string {
    return "id"
}

// Fields returns the model fields
func (u *User) Fields() map[string]interface{} {
    return map[string]interface{}{
        "id":         u.ID,
        "name":       u.Name,
        "email":      u.Email,
        "created_at": u.CreatedAt,
        "updated_at": u.UpdatedAt,
    }
}

// SetFields sets the model fields
func (u *User) SetFields(fields map[string]interface{}) {
    if id, ok := fields["id"].(int64); ok {
        u.ID = id
    }
    if name, ok := fields["name"].(string); ok {
        u.Name = name
    }
    if email, ok := fields["email"].(string); ok {
        u.Email = email
    }
    if createdAt, ok := fields["created_at"].(time.Time); ok {
        u.CreatedAt = createdAt
    }
    if updatedAt, ok := fields["updated_at"].(time.Time); ok {
        u.UpdatedAt = updatedAt
    }
}

// Create creates a new record
func (orm *ORM) Create(ctx context.Context, model Model) error {
    fields := model.Fields()
    delete(fields, model.PrimaryKey()) // Remove primary key for insert

    columns := make([]string, 0, len(fields))
    values := make([]interface{}, 0, len(fields))
    placeholders := make([]string, 0, len(fields))

    for column, value := range fields {
        columns = append(columns, column)
        values = append(values, value)
        placeholders = append(placeholders, "?")
    }

    query := fmt.Sprintf(
        "INSERT INTO %s (%s) VALUES (%s)",
        model.TableName(),
        strings.Join(columns, ", "),
        strings.Join(placeholders, ", "),
    )

    result, err := orm.db.ExecContext(ctx, query, values...)
    if err != nil {
        return err
    }

    id, err := result.LastInsertId()
    if err != nil {
        return err
    }

    // Set the ID on the model
    fields[model.PrimaryKey()] = id
    model.SetFields(fields)

    return nil
}

// Find finds a record by ID
func (orm *ORM) Find(ctx context.Context, model Model, id interface{}) error {
    query := fmt.Sprintf("SELECT * FROM %s WHERE %s = ?", model.TableName(), model.PrimaryKey())

    row := orm.db.QueryRowContext(ctx, query, id)

    // Get column names
    columns, err := row.Columns()
    if err != nil {
        return err
    }

    // Create slice of pointers
    values := make([]interface{}, len(columns))
    valuePtrs := make([]interface{}, len(columns))
    for i := range values {
        valuePtrs[i] = &values[i]
    }

    // Scan the row
    if err := row.Scan(valuePtrs...); err != nil {
        return err
    }

    // Create fields map
    fields := make(map[string]interface{})
    for i, column := range columns {
        fields[column] = values[i]
    }

    model.SetFields(fields)
    return nil
}

// Update updates a record
func (orm *ORM) Update(ctx context.Context, model Model) error {
    fields := model.Fields()
    id := fields[model.PrimaryKey()]
    delete(fields, model.PrimaryKey()) // Remove primary key from update

    columns := make([]string, 0, len(fields))
    values := make([]interface{}, 0, len(fields))

    for column, value := range fields {
        columns = append(columns, fmt.Sprintf("%s = ?", column))
        values = append(values, value)
    }

    query := fmt.Sprintf(
        "UPDATE %s SET %s WHERE %s = ?",
        model.TableName(),
        strings.Join(columns, ", "),
        model.PrimaryKey(),
    )

    values = append(values, id)

    _, err := orm.db.ExecContext(ctx, query, values...)
    return err
}

// Delete deletes a record
func (orm *ORM) Delete(ctx context.Context, model Model) error {
    fields := model.Fields()
    id := fields[model.PrimaryKey()]

    query := fmt.Sprintf("DELETE FROM %s WHERE %s = ?", model.TableName(), model.PrimaryKey())

    _, err := orm.db.ExecContext(ctx, query, id)
    return err
}

TL;DR Runbook

Quick Start

// 1. Connection pooling
config := PoolConfig{
    MaxOpenConns:    100,
    MaxIdleConns:    10,
    ConnMaxLifetime: time.Hour,
    ConnMaxIdleTime: time.Minute * 10,
}
pool, err := NewConnectionPool("postgres", dsn, config)

// 2. Transaction management
txManager := NewTransactionManager(pool.GetDB())
err := txManager.WithTransaction(ctx, func(tx *Transaction) error {
    // Perform database operations
    return nil
})

// 3. Query optimization
qb := NewQueryBuilder("users").
    Select("id", "name", "email").
    Where("active = ?", true).
    OrderBy("created_at", "DESC").
    Limit(10)

// 4. Migration management
migrationManager := NewMigrationManager(pool.GetDB())
migrationManager.AddMigration(Migration{
    Version: 1,
    Name:    "create_users_table",
    UpSQL:   "CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(255))",
    DownSQL: "DROP TABLE users",
})
err := migrationManager.Migrate(ctx)

Essential Patterns

// Prepared statements
cache := NewPreparedStatementCache(pool.GetDB())
result, err := cache.Execute(ctx, "INSERT INTO users (name, email) VALUES (?, ?)", name, email)

// Optimistic locking
locking := NewOptimisticLocking(pool.GetDB())
err := locking.UpdateWithOptimisticLock(ctx, "users", userID, currentVersion, updates)

// Query caching
queryCache := NewQueryCache(5*time.Minute, 1000)
results, err := queryCache.CachedQuery(ctx, pool.GetDB(), "SELECT * FROM users WHERE active = ?", true)

// ORM usage
orm := NewORM(pool.GetDB())
user := &User{Name: "John", Email: "john@example.com"}
err := orm.Create(ctx, user)

This guide provides the complete machinery for building robust database applications in Go. Each pattern includes implementation examples, performance considerations, and real-world usage patterns for enterprise deployment.