Skip to content

Transactions

Overview

GPA supports transactions through the Transaction[T] interface, which extends Repository[T] with commit, rollback, and savepoint support.

Basic Transactions

err := userRepo.Transaction(ctx, func(tx gpa.Transaction[User]) error {
    // All operations within this function are atomic
    if err := tx.Create(ctx, &User{Name: "Alice"}); err != nil {
        return err  // Rolls back the transaction
    }
    if err := tx.UpdatePartial(ctx, 1, map[string]interface{}{
        "name": "Bob",
    }); err != nil {
        return err  // Rolls back the transaction
    }
    return nil  // Commits the transaction
})

If the function returns an error, the transaction is rolled back. If it returns nil, the transaction is committed.

Nested Transactions and Savepoints

SQL providers support savepoints for nested transactions:

err := userRepo.Transaction(ctx, func(tx gpa.Transaction[User]) error {
    // Outer transaction
    tx.Create(ctx, &User{Name: "Alice"})

    // Create a savepoint
    tx.SetSavepoint("before_update")

    // This can be rolled back independently
    tx.UpdatePartial(ctx, 1, map[string]interface{}{"name": "Bob"})

    // Rollback to savepoint (undoes the update but keeps the create)
    if err := tx.RollbackToSavepoint("before_update"); err != nil {
        return err
    }

    return nil  // Commits only the create
})

Transaction Interface

type Transaction[T any] interface {
    Repository[T]
    Commit() error
    Rollback() error
    SetSavepoint(name string) error
    RollbackToSavepoint(name string) error
}

Provider Transaction Support

FeatureGORMBunMongoDBRedis
Commit/RollbackYesYesYesNo*
SavepointsYesNoNoNo
Isolation LevelsYes (ReadCommitted, RepeatableRead, Serializable)YesYesN/A

*Redis uses its own multi/exec model for atomic operations.