Transactions
Geode provides full ACID transaction guarantees with Multi-Version Concurrency Control (MVCC) and six isolation levels ranging from Read Uncommitted to Linearizable.
Overview
Transactions ensure data consistency and integrity even in the presence of concurrent access, system failures, and application errors. Geode’s transaction system combines ACID guarantees with high performance using MVCC (Multi-Version Concurrency Control) and Serializable Snapshot Isolation (SSI).
Whether you’re executing a single query or coordinating complex multi-step operations, Geode’s transaction support ensures your data remains consistent. Choose from six isolation levels to balance consistency requirements with performance needs.
ACID Guarantees
Atomicity
All operations in a transaction succeed or fail as a unit:
-- Begin transaction
BEGIN;
-- Multiple operations (all or nothing)
CREATE (:Person {name: 'Alice', email: 'alice@example.com'});
CREATE (:Person {name: 'Bob', email: 'bob@example.com'});
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS]->(b);
-- Commit (all changes applied) or Rollback (nothing applied)
COMMIT;
If any operation fails or ROLLBACK is called, all changes are discarded.
Consistency
Transactions move the database from one consistent state to another:
BEGIN;
-- Constraints enforced within transaction
CREATE (:Person {email: 'alice@example.com'});
-- This fails if email uniqueness constraint exists
CREATE (:Person {email: 'alice@example.com'});
ROLLBACK; -- Database remains consistent
Isolation
Concurrent transactions don’t interfere with each other:
-- Transaction 1
BEGIN;
MATCH (p:Person {name: 'Alice'})
SET p.age = 31;
-- Transaction 2 doesn't see uncommitted change
COMMIT;
Geode provides six isolation levels for different consistency requirements.
Durability
Committed transactions survive system failures:
BEGIN;
CREATE (:Person {name: 'Alice'});
COMMIT; -- Guaranteed durable via WAL
-- Even if system crashes immediately after COMMIT,
-- Alice will exist after recovery
Write-Ahead Logging (WAL) ensures durability with point-in-time recovery.
Topics in This Section
- Advanced Patterns - Advanced transaction patterns including savepoints, nested transactions, and optimistic concurrency control
Isolation Levels
Geode supports six isolation levels:
1. Read Uncommitted
Dirty reads allowed: See uncommitted changes from other transactions.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
-- May see uncommitted changes
MATCH (p:Person) RETURN p.name;
COMMIT;
Use Cases: Analytics queries where approximate data is acceptable.
2. Read Committed
Default: Only see committed changes.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
-- Only sees committed data
MATCH (p:Person) RETURN p.name;
COMMIT;
Use Cases: General-purpose transactions, web applications.
3. Repeatable Read
No non-repeatable reads: Same query returns same results within transaction.
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
MATCH (p:Person) RETURN count(*); -- Returns N
-- Other transactions commit changes
MATCH (p:Person) RETURN count(*); -- Still returns N
COMMIT;
Use Cases: Reports, financial calculations requiring consistency.
4. Snapshot
Point-in-time snapshot: Transaction sees database state at BEGIN time.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN;
-- Transaction sees snapshot from BEGIN time
MATCH (p:Person) RETURN p.name;
COMMIT;
Use Cases: Long-running read transactions, backups.
5. Serializable (Default)
Serializable Snapshot Isolation (SSI): Prevents all anomalies including phantoms.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
-- Guaranteed serializable execution
MATCH (p:Person) WHERE p.age > 30
CREATE (:Report {count: count(p)});
COMMIT;
Use Cases: Financial transactions, inventory management.
6. Linearizable
Strongest isolation: Real-time ordering with external consistency.
SET TRANSACTION ISOLATION LEVEL LINEARIZABLE;
BEGIN;
-- Guaranteed real-time ordering
CREATE (:Order {timestamp: now()});
COMMIT;
Use Cases: Distributed systems requiring strict ordering.
MVCC Architecture
Multi-Version Concurrency Control enables high concurrency:
How MVCC Works
- Version Creation: Each update creates new version of data
- Visibility: Transactions see appropriate version based on isolation level
- No Read Locks: Readers never block writers
- No Write Locks: Writers don’t block readers (different rows)
- Garbage Collection: Old versions cleaned up when no longer needed
Benefits
- High Concurrency: Readers and writers don’t block each other
- Consistent Snapshots: Transactions see consistent database state
- No Deadlocks: For read-only transactions
- Time-Travel: Historical queries possible
See: Advanced Patterns
Transaction Lifecycle
Basic Transaction
-- 1. Begin transaction
BEGIN;
-- 2. Execute operations
MATCH (p:Person {name: 'Alice'})
SET p.age = 31;
CREATE (:AuditLog {
action: 'UPDATE',
user: 'admin',
timestamp: now()
});
-- 3. Commit or rollback
COMMIT; -- Apply all changes
-- OR
ROLLBACK; -- Discard all changes
Auto-Commit Mode
Single statements auto-commit:
-- Implicitly wrapped in BEGIN...COMMIT
CREATE (:Person {name: 'Alice'});
Equivalent to:
BEGIN;
CREATE (:Person {name: 'Alice'});
COMMIT;
Explicit Transactions
Multiple statements in one transaction:
BEGIN;
-- Statement 1
CREATE (:Person {name: 'Alice'});
-- Statement 2
CREATE (:Person {name: 'Bob'});
-- Statement 3
MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS]->(b);
COMMIT;
Savepoints
Create rollback points within transactions:
BEGIN;
-- Create person
CREATE (:Person {name: 'Alice', email: 'alice@example.com'});
-- Savepoint after person creation
SAVEPOINT person_created;
-- Create order (might fail)
CREATE (:Order {customer: 'Alice', total: 100.00});
-- If order creation fails, rollback to savepoint
ROLLBACK TO SAVEPOINT person_created;
-- Person still exists, order doesn't
COMMIT;
Use Cases:
- Partial rollback on errors
- Nested transaction simulation
- Complex multi-step operations
See: Advanced Patterns
Transaction Patterns
Optimistic Concurrency Control
-- 1. Read with version
MATCH (p:Product {id: 123})
RETURN p.stock, p.version;
-- 2. Business logic (outside database)
new_stock = current_stock - quantity;
-- 3. Update with version check
MATCH (p:Product {id: 123})
WHERE p.version = $read_version
SET p.stock = $new_stock,
p.version = p.version + 1;
-- If version doesn't match, retry
Pessimistic Locking
BEGIN;
-- Lock row for update
MATCH (p:Product {id: 123})
SET p.locked = true;
-- Perform operations
SET p.stock = p.stock - 1;
-- Unlock
SET p.locked = false;
COMMIT;
Retry Pattern
import asyncio
from geode_client import QueryError
async def execute_with_retry(client, query, max_retries=3):
for attempt in range(max_retries):
async with client.connection() as conn:
await conn.begin()
try:
page, _ = await conn.query(query)
await conn.commit()
return page.rows
except QueryError as exc:
await conn.rollback()
if attempt == max_retries - 1:
raise
# Exponential backoff
await asyncio.sleep(2 ** attempt)
Batch Processing
BEGIN;
-- Process in batches to avoid long-running transactions
MATCH (p:Person)
WHERE p.processed = false
WITH p LIMIT 1000
SET p.processed = true,
p.processed_at = now();
COMMIT;
-- Repeat until all processed
See: Advanced Patterns for more patterns.
Error Handling
Transaction Errors
BEGIN;
-- First operation succeeds
CREATE (:Person {name: 'Alice'});
-- Second operation fails (constraint violation)
CREATE (:Person {email: 'alice@example.com'}); -- Duplicate
-- Error: Unique constraint violation
-- Entire transaction rolls back automatically
-- Alice is NOT created
Serialization Errors
BEGIN;
-- Read data
MATCH (p:Product {id: 123}) RETURN p.stock;
-- Another transaction updates same product
-- Update fails with serialization error
MATCH (p:Product {id: 123})
SET p.stock = p.stock - 1;
-- Error: Serialization failure, retry transaction
ROLLBACK;
Solution: Retry with exponential backoff.
Deadlock Detection
-- Transaction 1
BEGIN;
MATCH (a:Account {id: 1}) SET a.balance = a.balance - 100;
-- Transaction 2 locks account 2
MATCH (b:Account {id: 2}) SET b.balance = b.balance + 100;
-- Deadlock detected!
-- Error: Deadlock detected, transaction aborted
ROLLBACK;
Geode automatically detects and resolves deadlocks.
Performance Considerations
Transaction Size
- Keep Transactions Small: Large transactions increase conflict probability
- Batch Appropriately: Balance between transaction overhead and size
- Avoid Long-Running Transactions: Blocks MVCC garbage collection
Isolation Level Trade-offs
| Isolation Level | Consistency | Concurrency | Use Case |
|---|---|---|---|
| Read Uncommitted | Lowest | Highest | Analytics |
| Read Committed | Medium | High | Web apps |
| Repeatable Read | High | Medium | Reports |
| Snapshot | High | Medium | Backups |
| Serializable | Highest | Low | Financial |
| Linearizable | Strongest | Lowest | Distributed |
Monitoring
-- Check active transactions
SELECT * FROM system.active_transactions;
-- Check transaction conflicts
SELECT * FROM system.transaction_conflicts;
-- Average transaction duration
SELECT avg(duration) FROM system.completed_transactions;
Best Practices
Transaction Design
- Keep transactions short: Minimize hold time
- Choose appropriate isolation level: Balance consistency and performance
- Handle serialization errors: Implement retry logic
- Use savepoints: For partial rollback capability
- Avoid user interaction: Within transaction scope
Error Handling
- Always use try/finally: Ensure rollback on errors
- Retry serialization errors: With exponential backoff
- Log transaction failures: For debugging and monitoring
- Set transaction timeout: Prevent runaway transactions
Testing
- Test concurrent scenarios: Simulate concurrent users
- Test failure scenarios: Rollback, serialization errors
- Load test: Measure transaction throughput
- Monitor metrics: Track transaction duration and conflicts
Learn More
- Advanced Patterns - Savepoints and advanced patterns
- Architecture: Transaction Management - MVCC implementation
- Performance Tuning - Optimize transaction performance
- Client Libraries - Language-specific transaction APIs
Examples
Transfer Between Accounts
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Deduct from source account
MATCH (source:Account {id: $from_account})
WHERE source.balance >= $amount
SET source.balance = source.balance - $amount;
-- Add to destination account
MATCH (dest:Account {id: $to_account})
SET dest.balance = dest.balance + $amount;
-- Create audit trail
CREATE (:Transaction {
from: $from_account,
to: $to_account,
amount: $amount,
timestamp: now()
});
COMMIT;
Inventory Management
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Check stock availability
MATCH (p:Product {sku: $product_sku})
WHERE p.stock >= $quantity
SET p.stock = p.stock - $quantity;
-- Create order
CREATE (o:Order {
order_id: $order_id,
product_sku: $product_sku,
quantity: $quantity,
created_at: now()
});
-- Link to customer
MATCH (c:Customer {id: $customer_id})
CREATE (c)-[:PLACED]->(o);
COMMIT;
Next Steps
- Learn Advanced Patterns - Master savepoints and patterns
- Practice with Tutorials - Hands-on examples
- Optimize Performance - Transaction performance tuning