q.Transaction wraps GORM’s transaction: the callback receives a *query.Query bound to the transaction; returning an error (or panicking) rolls back, returning nil commits. Isolation can be set with the standard *sql.TxOptions:
// check tx.Error — a failed BEGIN leaves the transaction unusable if tx.Error != nil { return tx.Error } defer tx.Rollback() // no-op after Commit
// do some database operations in the transaction (use 'tx' from this point, not 'db') tx.User.WithContext(ctx).Create(...)
// ...
// rollback the transaction in case of error tx.Rollback()
// Or commit the transaction tx.Commit()
For example:
q := query.Use(db)
funcdoSomething(ctx context.Context, users ...*model.User) (err error) { tx := q.Begin() if tx.Error != nil { return tx.Error } // Panic policy: on a panic we roll back and re-panic so the caller sees it; // on a returned error we roll back and report it normally. deferfunc() { if r := recover(); r != nil { _ = tx.Rollback() panic(r) } }() deferfunc() { if err != nil { _ = tx.Rollback() } }()
q.Begin also accepts *sql.TxOptions. It returns a *query.QueryTx, which embeds the full *query.Query, so all DAOs are available on tx (tx.User, tx.Order, …), plus Commit / Rollback / SavePoint / RollbackTo.
SavePoint/RollbackTo
GEN provides SavePoint, RollbackTo to save points and roll back to a savepoint, for example: