ACID Transactions

Perform atomic, consistent, isolated, and durable multi-document operations with SoliDB's powerful transaction engine.

Overview

SoliDB supports fully ACID-compliant transactions across multiple documents and collections. Transactions are managed via a Write-Ahead Log (WAL) to ensure durability even in the event of a system crash.

Key Properties

  • Atomic: All operations succeed or none do.
  • Consistent: Database moves from one valid state to another.
  • Isolated: Transactions are invisible to others until committed.
  • Durable: Committed changes are permanently saved.

How it works

Transactions are initiated via the API, returning a Transaction ID (tx_id). All subsequent operations using this ID are staged in memory and the WAL. Changes are only applied to the main storage engines upon COMMIT.

Isolation Levels

SoliDB supports configurable isolation levels to balance consistency and performance. The default is Read Committed.

Read Uncommitted

Fastest

Transactions can see uncommitted changes from other transactions. "Dirty reads" are possible.

Read Committed

Default

Transactions only see data that has been committed. Prevents dirty reads but allows non-repeatable reads.

Repeatable Read

Consistent

Ensures that if you read a row twice, you get the same result. Prevents dirty and non-repeatable reads.

Serializable

Strictest

Transactions are executed as if they happened serially. Prevents all concurrency anomalies including phantom reads.

Basic Usage

Transactions are handled via HTTP endpoints. The workflow is: Begin → Perform Operations → Commit (or Rollback).

1 Begin Transaction

# Request
POST /_api/database/mydb/transaction/begin
{ "isolationLevel": "read_committed" }
# Response
{ "id": "tx:1678901234", "status": "active" }

2 Execute Operations

Use the returned tx_id in the URL path.

# Insert Document
POST /_api/database/mydb/transaction/tx:1678901234/document/users
{ "name": "Alice", "balance": 100 }
# Update Document
PUT /_api/database/mydb/transaction/tx:1678901234/document/users/user_123
{ "balance": 90 }

3 Commit

# Request
POST /_api/database/mydb/transaction/tx:1678901234/commit
# Response
{ "status": "committed" }

Transactional SDBQL

You can also execute complex queries, including conditional logic and batch updates, within a transaction.

# Execute Query in Transaction
POST /_api/database/mydb/transaction/tx:1678901234/query
{
  "query": "FOR u IN users FILTER u.active == true UPDATE u WITH { status: 'processed' } IN users"
}

Transactional SDBQL queries act as "staged" operations. If the query contains INSERT, UPDATE, or REMOVE, the changes are not visible to other clients until you call COMMIT.

Lua Scripting

Transactions can be executed directly within Lua scripts for maximum performance and atomicity. The db:transaction function handles the commit/rollback logic automatically.

-- Execute Transaction in Lua
db:transaction
(function(tx)
-- Get transactional collection handles
local users = tx:collection("users")
local logs = tx:collection("audit_logs")

-- Perform operations
users:update("user_123", { balance = 90 })
logs:insert({ action = "transfer", amount = 10, user = "user_123" })
end)

If the callback function throws an error, the transaction is automatically rolled back. If it creates a return value, the transaction is committed and the value is returned.

Limitations

  • Graph Traversals: Multi-hop graph queries are not yet supported inside transactions.
  • Aggregations: The COLLECT statement is currently read-only and cannot be used in a transactional mutation query.
  • Constraint Violations: Unique index violations will cause the COMMIT to fail and automatically rollback the entire transaction.