Transactions¶
Multi-record transactions group several record operations into a single atomic unit. Writes become visible together at commit, or are rolled back together on abort.
Server Requirements¶
Transactions require Aerospike Server 8.0+ with the target namespace configured for strong consistency. On an AP namespace the transaction APIs raise immediately; on an SC namespace the server allocates a transaction monitor record and tracks the write set.
Async¶
Use Session.begin_transaction() as a context manager. The returned
TransactionalSession auto-attaches
the transaction to every operation — application code never sees the
Txn object itself. On clean exit the transaction commits; on any
exception it aborts.
from aerospike_sdk import Client, Behavior, DataSet
async with Client("localhost:3100") as client:
session = client.create_session(Behavior.DEFAULT)
accounts = DataSet.of("test_sc", "accounts")
async with session.begin_transaction() as tx:
await tx.upsert(accounts.id("A")).bin("bal").add(-10).execute()
await tx.upsert(accounts.id("B")).bin("bal").add(10).execute()
If anything inside the with raises, the transaction is aborted and the
exception propagates.
Retrying on Transient Conflicts¶
Strong-consistency transactions can fail with transient conflicts when
concurrent writers touch the same record
(MRT_BLOCKED, MRT_VERSION_MISMATCH, TXN_FAILED). Use
do_in_transaction to retry the whole block automatically:
async def transfer(tx):
await tx.upsert(accounts.id("A")).bin("bal").add(-10).execute()
await tx.upsert(accounts.id("B")).bin("bal").add(10).execute()
return "ok"
result = await session.do_in_transaction(
transfer,
max_attempts=5,
sleep_between_retries=0.01,
)
Non-transient errors raised inside the callable abort the transaction and re-raise without retry.
Sync¶
The synchronous API mirrors the async surface exactly — just drop the
async/await:
from aerospike_sdk import SyncClient, Behavior, DataSet
with SyncClient("localhost:3100") as client:
session = client.create_session(Behavior.DEFAULT)
accounts = DataSet.of("test_sc", "accounts")
with session.begin_transaction() as tx:
tx.upsert(accounts.id("A")).bin("bal").add(-10).execute()
tx.upsert(accounts.id("B")).bin("bal").add(10).execute()
do_in_transaction is available on
SyncSession as well, with a
time.sleep-based retry loop.
Reads Inside a Transaction¶
Reads issued inside begin_transaction participate in the transaction
and see a consistent snapshot of the write set:
async with session.begin_transaction() as tx:
stream = await tx.query(accounts.id("A")).execute()
current = (await stream.first_or_raise()).record.bins["bal"]
if current >= 10:
await tx.upsert(accounts.id("A")).bin("bal").add(-10).execute()
Errors¶
Error |
Meaning |
|---|---|
|
Commit failed (server-side); the transaction is in an indeterminate state. |
|
Another transaction has one of the records locked. Retry. |
|
A non-transactional write raced with the transaction. Retry. |
|
Transaction monitor TTL elapsed before commit. |
|
Exceeded the per-transaction write limit. |
See Also:
TransactionalSession— async API referenceSyncTransactionalSession— sync API reference