Transactions allow you to execute a group of queries atomically, meaning either all changes are applied or none are. This is essential for maintaining data consistency when performing related operations that must not be partially applied.
| Method | Description |
|---|---|
db.beginTransaction() | Starts a new transaction |
txn.commit() | Commits the transaction, applying all changes |
txn.cancel() | Cancels the transaction, discarding all changes |
Call .beginTransaction() on any Surreal or SurrealSession instance to start a new transaction. The returned SurrealTransaction object provides all the same query methods as a regular session, but every operation is executed within the transaction scope.
const txn = await db.beginTransaction();
Use the transaction object to execute queries just as you would on the Surreal instance. All operations are held in a pending state until you commit or cancel.
const txn = await db.beginTransaction(); await txn.create(new RecordId('users', 'alice')) .content({ name: 'Alice', email: 'alice@example.com' }); await txn.create(new RecordId('users', 'bob')) .content({ name: 'Bob', email: 'bob@example.com' });
Call .commit() to apply all pending changes to the database. After committing, the transaction cannot be used again.
await txn.commit();
Call .cancel() to discard all pending changes. This is typically done when an error occurs during the transaction. After cancelling, the transaction cannot be used again.
await txn.cancel();
Always wrap transaction logic in a try-catch block to ensure the transaction is cancelled if any operation fails. This prevents partial changes from being committed.
const txn = await db.beginTransaction(); try { const from = await txn.select(new RecordId('accounts', 'alice')); const to = await txn.select(new RecordId('accounts', 'bob')); if (from.balance < 100) { throw new Error('Insufficient funds'); } await txn.update(new RecordId('accounts', 'alice')) .merge({ balance: from.balance - 100 }); await txn.update(new RecordId('accounts', 'bob')) .merge({ balance: to.balance + 100 }); await txn.commit(); } catch (error) { await txn.cancel(); throw error; }
Execute transactions quickly to avoid holding resources longer than necessary. Perform any validation or external API calls before starting the transaction.
if (!isValidEmail(email)) { throw new Error('Invalid email'); } const txn = await db.beginTransaction(); await txn.create(new RecordId('users', id)).content({ email }); await txn.commit();
Once a transaction is committed or cancelled, create a new one for subsequent operations.
const txn1 = await db.beginTransaction(); await txn1.create(record1).content(data1); await txn1.commit(); const txn2 = await db.beginTransaction(); await txn2.create(record2).content(data2); await txn2.commit();