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

MethodDescription
db.Begin(ctx)Starts a transaction on the default session
session.Begin(ctx)Starts a transaction within a session
tx.Commit(ctx)Commits the transaction, applying all changes
tx.Cancel(ctx)Cancels the transaction, discarding all changes
tx.ID()Returns the transaction's UUID
tx.IsClosed()Returns whether the transaction has been committed or canceled

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)

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