How do I handle deadlocks and serialization errors using pgx?

Handling deadlocks and serialization errors in Go when using the pgx package is crucial for maintaining database integrity and application stability. This guide provides insights into managing these issues effectively.
Deadlocks, Serialization errors, pgx, Go, Database management, Error handling
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/jackc/pgx/v4"
    "github.com/jackc/pgx/v4/pgxpool"
)

func main() {
    // Establish connection to the database
    config, err := pgxpool.ParseConfig("postgres://user:password@localhost:5432/database")
    if err != nil {
        log.Fatal("Unable to parse connection string:", err)
    }

    pool, err := pgxpool.ConnectConfig(context.Background(), config)
    if err != nil {
        log.Fatal("Unable to connect to database:", err)
    }
    defer pool.Close()

    // Example transaction with deadlock handling
    err = handleTransaction(pool)
    if err != nil {
        log.Println("Transaction failed:", err)
    }
}

func handleTransaction(pool *pgxpool.Pool) error {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    // Attempt to begin a transaction
    tx, err := pool.Begin(ctx)
    if err != nil {
        return fmt.Errorf("failed to start transaction: %w", err)
    }

    // Ensure the transaction is rolled back if there is an error
    defer func() {
        if err != nil {
            tx.Rollback(ctx)
        }
    }()

    // Execute some SQL operations
    _, err = tx.Exec(ctx, "UPDATE accounts SET balance = balance - 100 WHERE id = $1", 1)
    if err != nil {
        if pgErr, ok := err.(pgconn.PgError); ok {
            // Handle specific PostgreSQL errors
            switch pgErr.SQLState() {
            case "40P01": // Deadlock detected
                return fmt.Errorf("deadlock detected: %w", err)
            case "40001": // Serialization failure
                return fmt.Errorf("serialization failure: %w", err)
            }
        }
        return fmt.Errorf("failed to execute query: %w", err)
    }

    // Commit the transaction
    if err = tx.Commit(ctx); err != nil {
        return fmt.Errorf("failed to commit transaction: %w", err)
    }

    return nil
}

Deadlocks Serialization errors pgx Go Database management Error handling