Transactions
Interactive transactions let you group multiple operations into an atomic unit. Unlike text-based transactions (BEGIN TRANSACTION; ... COMMIT; — see the query builder for composing those), interactive transactions allow you to execute statements one at a time, inspect results, and conditionally decide whether to commit or cancel.
Transactions require a WebSocket connection (ws:// or wss://) and SurrealDB v3 or later.
API References
Starting a transaction
Call .Begin() on a *DB or *Session to start a transaction. The transaction inherits the authentication and namespace context from the connection or session that started it.
tx, err := db.Begin(ctx)
if err != nil {
log.Fatal(err)
}
defer tx.Cancel(ctx)
Always use defer tx.Cancel(ctx) immediately after .Begin(). If the transaction has already been committed, .Cancel() returns ErrTransactionClosed but does not cause any harm.
Executing operations within a transaction
Transactions satisfy the sendable constraint, so all generic functions like Query, Select, Create, Update, and Delete accept a *Transaction.
tx, err := db.Begin(ctx)
if err != nil {
log.Fatal(err)
}
defer tx.Cancel(ctx)
_, err = surrealdb.Create[any](ctx, tx, models.Table("accounts"), map[string]any{
"name": "Alice",
"balance": 1000,
})
if err != nil {
log.Fatal(err)
}
_, err = surrealdb.Create[any](ctx, tx, models.Table("accounts"), map[string]any{
"name": "Bob",
"balance": 500,
})
if err != nil {
log.Fatal(err)
}
if err := tx.Commit(ctx); err != nil {
log.Fatal(err)
}
Changes made within a transaction are not visible to other connections or sessions until the transaction is committed.
Conditional commit or cancel
Because interactive transactions let you inspect results between operations, you can decide whether to commit based on runtime conditions.
tx, err := db.Begin(ctx)
if err != nil {
log.Fatal(err)
}
defer tx.Cancel(ctx)
results, err := surrealdb.Query[[]map[string]any](ctx, tx,
"SELECT * FROM accounts WHERE name = 'Alice'",
nil,
)
if err != nil {
log.Fatal(err)
}
balance, ok := (*results)[0].Result[0]["balance"].(float64)
if !ok || balance < 100 {
fmt.Println("Insufficient balance, canceling")
return
}
_, err = surrealdb.Query[[]any](ctx, tx,
"UPDATE accounts SET balance -= 100 WHERE name = 'Alice'; UPDATE accounts SET balance += 100 WHERE name = 'Bob';",
nil,
)
if err != nil {
log.Fatal(err)
}
if err := tx.Commit(ctx); err != nil {
log.Fatal(err)
}
Transaction limitations
Transactions do not support session state changes. The following operations are not available on a *Transaction:
The namespace, database, authentication, and variables are inherited from the *DB or *Session that started the transaction.
Learn more