How to Implement Pessimistic Locking in Go

Implement pessimistic locking in Go by using database transactions with serializable isolation and FOR UPDATE clauses to block concurrent access.

Implement pessimistic locking in Go by wrapping database transactions with sql.Tx and using sql.TxOptions{Isolation: sql.LevelSerializable} to ensure exclusive access. This approach blocks other transactions from reading or writing the same data until the current transaction commits or rolls back.

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func updateBalance(db *sql.DB, accountID int, amount int64) error {
    tx, err := db.BeginTx(nil, &sql.TxOptions{
        Isolation: sql.LevelSerializable,
        ReadOnly:  false,
    })
    if err != nil {
        return err
    }
    defer tx.Rollback()

    var currentBalance int64
    if err := tx.QueryRow("SELECT balance FROM accounts WHERE id = $1 FOR UPDATE", accountID).Scan(&currentBalance); err != nil {
        return err
    }

    if _, err := tx.Exec("UPDATE accounts SET balance = $1 WHERE id = $2", currentBalance+amount, accountID); err != nil {
        return err
    }

    return tx.Commit()
}