BEGIN TRANSACTION — all-or-nothing blocks

View .md

Turn a script into one all-or-nothing native transaction. The editor validates every rule at the keystroke — where DynamoDB would report an opaque cancellation after the run, the studio catches violations before the wire. Write blocks use a deliberate two-step run (first Run previews the plan, an unchanged second Run commits) and carry an idempotency token, so a retry is a no-op rather than a double-apply.

Syntax

sql
BEGIN TRANSACTION;statement;            -- writes only, or reads only — never mixedstatement;            -- each write targets ONE item by its full key…;                    -- up to 100 statements, each item at most onceCOMMIT;

Extra WHERE conditions compile to an atomic ConditionExpression; arithmetic SET compiles to a native UpdateExpression; anything the native form can't express identically is an honest refusal naming the fix, never a silent drop. Clock functions share one instant across the block. Guide: Writes & transactions.

Use cases

Move money with a balance guard Native

Debit, credit, and the audit event land together or not at all — and the balance >= 100 predicate becomes a native condition, so an uncovered debit cancels the whole block.

sql
BEGIN TRANSACTION;UPDATE "stage.Users" SET balance = balance - 100  WHERE pk = 'User#9' AND sk = 'PROFILE' AND balance >= 100;UPDATE "stage.Users" SET balance = balance + 100  WHERE pk = 'User#12' AND sk = 'PROFILE';INSERT INTO "stage.Outbox" VALUE {'pk': 'Outbox#transfers', 'sk': 'TX#124', 'amount': 100};COMMIT;
Executes asTransactWriteItems · [ UpdateItem ×2 · PutItem ×1 ] · ClientRequestToken set
  • A cancellation reports per-statement reasons instead of DynamoDB's opaque error; the status line reports the billed capacity (· 3 WCU).
Create related items together Native

A new order plus the outbox event that announces it — two tables that must never disagree, written as one. The transactional-outbox pattern, in two statements.

sql
BEGIN TRANSACTION;INSERT INTO "stage.Orders" VALUE {'pk': 'Tenant#acme', 'sk': 'Order#9007',  'status': 'open', 'createdAt': CURRENT_TIMESTAMP};INSERT INTO "stage.Outbox" VALUE {'pk': 'Outbox#demo', 'sk': 'EVT#0002',  'Type': 'OrderCreated', 'Status': 'pending', 'CreatedAt': CURRENT_TIMESTAMP};COMMIT;
Executes asTransactWriteItems · PutItem ×2 — both stamped with the same instant
  • Clock functions render one shared instant across the block — the two timestamps can't drift, even across tables.
Read two accounts from one consistent snapshot Native

Comparing balances mid-transfer lies unless both reads see the same instant — a read transaction serves every item from a single snapshot, which no sequence of individual reads can guarantee.

sql
BEGIN TRANSACTION;SELECT * FROM "stage.Users" WHERE pk = 'User#9' AND sk = 'PROFILE';SELECT * FROM "stage.Users" WHERE pk = 'User#12' AND sk = 'PROFILE';COMMIT;
Executes asTransactGetItems · 2 exact-key reads · one consistent snapshot
  • Reads skip the two-step ritual (nothing to double-apply) and run fine against a read-only stage. Each SELECT must be an exact key lookup — no extra predicates, LIMIT, ORDER BY, or aggregates.

Compose a transaction with reads using THEN

sql
SELECT pk, balanceFROM "stage.Users"WHERE pk IN ('User#9', 'User#12') AND sk = 'PROFILE';THENBEGIN TRANSACTION;UPDATE "stage.Users" SET balance = balance - 100  WHERE pk = 'User#9' AND sk = 'PROFILE' AND balance >= 100;UPDATE "stage.Users" SET balance = balance + 100  WHERE pk = 'User#12' AND sk = 'PROFILE';COMMIT;THENSELECT pk, balanceFROM "stage.Users"WHERE pk IN ('User#9', 'User#12') AND sk = 'PROFILE'ORDER BY pk;

A standalone THEN line connects SELECT and complete write transaction units into one success-gated workflow. Units run top to bottom and the first failure skips everything after it. This makes “read before, commit, verify after” explicit without pretending the three units share one transaction.

  • The first SELECT is an independent read. If it fails, the transaction never starts.
  • The BEGIN … COMMIT block is the only atomic unit. Once it commits, later failures cannot roll it back.
  • The final SELECT starts only after the transaction succeeds. If it fails, the status reports partial completion because the transaction already committed.
  • A workflow containing writes uses a two-step confirmation for the whole unchanged workflow; a read-only workflow runs immediately.

Try it

Try it · TransactionSample
Executes asTransactWriteItems · 2 writes
TransactWriteItems [ UpdateItem ×2 ] · ConditionExpression on User#9: balance >= :v · ClientRequestToken set
All-or-nothing: if User#9 can't cover the debit, neither write lands.
Two-step run: first Run validates and previews; an unchanged second Run commits.
✓ Committed · 2 writes applied atomically · 2 WCU · idempotency token retained

Related: Writes & transactions · UPDATE · INSERT & upserts · keyword reference.

Was this page helpful?