Documentation
¶
Overview ¶
Package mysql provides a minimal shared MySQL abstraction for backend services.
The package intentionally stays small: it owns connection setup, read/write replica selection, tracing/metrics wrappers, transaction helpers, and MySQL-specific error classification. Query logic stays in caller packages. This keeps Bazel cache keys stable for dependents and avoids pulling service-specific SQL concerns into a base dependency.
New requires [Config.PrimaryDSN] and enforces `parseTime=true` in DSNs so datetime values decode correctly. When [Config.ReadOnlyDSN] is empty, reads and writes use the same underlying pool. Use [Database.RW] for writes and [Database.RO] for read paths.
Generated query code should depend on DBTX, so the same query methods can run against either a Replica or a transaction. Use Tx / TxWithResult for single-attempt transactions, and TxRetry / TxWithResultRetry when the operation is safe to retry on transient failures.
Retry helpers only retry errors classified as transient by IsTransientError. IsNotFound and IsDuplicateKeyError are treated as terminal and are not retried.
Index ¶
- Constants
- func IsConnectionError(err error) bool
- func IsDeadlockError(err error) bool
- func IsDuplicateKeyError(err error) bool
- func IsLockWaitTimeoutError(err error) bool
- func IsNotFound(err error) bool
- func IsTooManyConnectionsError(err error) bool
- func IsTransientError(err error) bool
- func New(config Config) (*database, error)
- func NewFromReplicas(ro, rw *Replica) *database
- func Tx(ctx context.Context, db *Replica, fn func(context.Context, DBTX) error) error
- func TxRetry(ctx context.Context, db *Replica, fn func(context.Context, DBTX) error) error
- func TxWithResult[T any](ctx context.Context, db *Replica, fn func(context.Context, DBTX) (T, error)) (T, error)
- func TxWithResultRetry[T any](ctx context.Context, db *Replica, fn func(context.Context, DBTX) (T, error)) (T, error)
- func WithRetryContext[T any](ctx context.Context, fn func() (T, error)) (T, error)
- type Config
- type DBTX
- type DBTx
- type Database
- type MySQL
- type Replica
- func (r *Replica) Begin(ctx context.Context) (DBTx, error)
- func (r *Replica) Close() error
- func (r *Replica) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
- func (r *Replica) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (r *Replica) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
- func (r *Replica) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
- type TracedTx
- func (t *TracedTx) Commit() error
- func (t *TracedTx) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
- func (t *TracedTx) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
- func (t *TracedTx) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
- func (t *TracedTx) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
- func (t *TracedTx) Rollback() error
Constants ¶
const ( // DefaultBackoff is the base duration for exponential backoff in database retries DefaultBackoff = 50 * time.Millisecond // DefaultAttempts is the maximum number of retry attempts for database operations DefaultAttempts = 3 )
Variables ¶
This section is empty.
Functions ¶
func IsConnectionError ¶
IsConnectionError returns true if the error indicates a connection problem.
func IsDeadlockError ¶
IsDeadlockError returns true if the error is a MySQL deadlock error (1213).
func IsDuplicateKeyError ¶
IsDuplicateKeyError reports whether err is MySQL error 1062 (duplicate key / unique constraint violation).
func IsLockWaitTimeoutError ¶
IsLockWaitTimeoutError returns true if the error is a MySQL lock wait timeout error (1205).
func IsNotFound ¶
IsNotFound returns true if the error is sql.ErrNoRows. Use this for consistent not-found handling across the codebase.
func IsTooManyConnectionsError ¶
IsTooManyConnectionsError returns true if the error is a MySQL too many connections error (1040).
func IsTransientError ¶
IsTransientError returns true if the error is a transient MySQL error that should be retried.
func New ¶
New creates a new database instance with the provided configuration. It establishes connections to the primary database and optionally to a read-only replica. Returns an error if connections cannot be established or if DSNs are misconfigured.
func NewFromReplicas ¶
func NewFromReplicas(ro, rw *Replica) *database
NewFromReplicas creates a MySQL from pre-existing replicas without opening new connections. This is a temporary bridge used by pkg/db.ToMySQL while callers migrate from pkg/db to pkg/mysql. Remove alongside NewReplicaFromDB and pkg/db.ToMySQL once all callers use New directly.
func Tx ¶
Tx executes fn within a database transaction without returning a result. It is a convenience wrapper around TxWithResult for operations that only need error handling.
func TxRetry ¶
TxRetry executes a transaction with automatic retry on transient errors like deadlocks. It is a convenience wrapper around TxWithResultRetry for operations that don't return a value.
func TxWithResult ¶
func TxWithResult[T any](ctx context.Context, db *Replica, fn func(context.Context, DBTX) (T, error)) (T, error)
TxWithResult executes fn within a database transaction and returns the result. It begins a transaction on db, executes fn with the transaction context, and commits on success or rolls back on failure.
Types ¶
type Config ¶
type Config struct {
// The primary DSN for your database. This must support both reads and writes.
PrimaryDSN string
// The readonly replica will be used for most read queries.
// If omitted, the primary is used.
ReadOnlyDSN string
}
Config defines the parameters needed to establish database connections. It supports separate connections for read and write operations to allow for primary/replica setups.
type DBTX ¶
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
DBTX is an interface that abstracts database operations for both direct connections and transactions. It allows query methods to work with either a database or transaction, making transaction handling more flexible.
This interface is implemented by both sql.DB and sql.Tx, as well as the custom Replica type in this package.
type DBTx ¶
DBTx represents a database transaction with commit and rollback capabilities. It extends DBTX with transaction-specific methods.
type Database ¶
type Database = MySQL
backwards compatible type until we move all services to use the MySQL interface directly
type MySQL ¶
type MySQL interface {
// RW returns the write (primary) replica for write operations
RW() *Replica
// RO returns the read replica for read operations
// If no read replica is configured, it returns the write replica
RO() *Replica
// Close properly terminates all database connections
Close() error
}
MySQL defines the interface for database operations, providing access to read and write replicas and the ability to close connections.
type Replica ¶
type Replica struct {
// contains filtered or unexported fields
}
Replica wraps a standard SQL database connection and implements the DBTX interface to enable interaction with the generated database code.
func NewReplicaFromDB ¶
NewReplicaFromDB wraps an existing *sql.DB as a *Replica with tracing and metrics. This is a temporary bridge used by pkg/db.ToMySQL while callers migrate from pkg/db to pkg/mysql. Remove alongside NewFromReplicas and pkg/db.ToMySQL once all callers use New directly.
func (*Replica) Begin ¶
Begin starts a transaction and returns it. This method provides a way to use the Replica in transaction-based operations.
func (*Replica) ExecContext ¶
ExecContext executes a SQL statement and returns a result summary. It's used for INSERT, UPDATE, DELETE statements that don't return rows.
func (*Replica) PrepareContext ¶
PrepareContext prepares a SQL statement for later execution.
func (*Replica) QueryContext ¶
QueryContext executes a SQL query that returns rows.
type TracedTx ¶
type TracedTx struct {
// contains filtered or unexported fields
}
TracedTx wraps a sql.Tx to add tracing to all database operations within a transaction
func (*TracedTx) ExecContext ¶
ExecContext executes a SQL statement within the transaction with tracing
func (*TracedTx) PrepareContext ¶
PrepareContext prepares a SQL statement within the transaction with tracing
func (*TracedTx) QueryContext ¶
QueryContext executes a SQL query within the transaction with tracing
func (*TracedTx) QueryRowContext ¶
QueryRowContext executes a SQL query that returns a single row within the transaction with tracing