DynamoDB Transactions
Eine DynamoDB-Transaktion gruppiert mehrere Schreibvorgänge zu einer einzigen Alles-oder-nichts-Operation: Entweder werden alle Aktionen committet, oder keine. So verhinderst du, dass zwei zusammengehörige Items auseinanderdriften, wenn ein Schreibvorgang nur halb gelingt.
Im Audit-Log-Szenario soll jedes Event, das du anhängst, auch einen
mandantenspezifischen eventCount erhöhen. Wenn das Event landet, der Zähler aber
nicht — oder umgekehrt —, stimmen Log und Zähler für immer nicht überein. Eine
Transaktion macht das unmöglich.
Unterstützt DynamoDB Transaktionen?
Ja. DynamoDB unterstützt ACID-Transaktionen über TransactWriteItems und
TransactGetItems, die bis zu 100 Aktionen in einer einzigen
Alles-oder-nichts-Operation über eine oder mehrere Tabellen gruppieren. Entweder
werden alle Schreibvorgänge committet oder keiner — zusammengehörige Items können
nicht auseinanderdriften. Transaktionale Schreibvorgänge kosten die doppelte
Kapazität normaler Schreibvorgänge, und eine fehlgeschlagene Bedingung oder ein
Konflikt bricht die gesamte Anfrage ab.
TransactWriteItemsgruppiert bis zu 100 Schreibaktionen über eine oder mehrere Tabellen, alles oder nichts. Die aggregierte Item-Größe darf 4 MB nicht überschreiten.- Aktionen sind
Put,Update,DeleteundConditionCheck. EinConditionCheckprüft eine Bedingung an einem Item, das du nicht schreibst. - Es kostet doppelt. Ein transaktionaler Schreibvorgang verbraucht die doppelte Kapazität eines normalen Schreibvorgangs — DynamoDB bereitet vor und committet dann.
- Konflikte und fehlgeschlagene Bedingungen brechen das Ganze ab mit einer
TransactionCanceledException; nichts Halbes bleibt zurück.
Das Problem: zwei Schreibvorgänge, die übereinstimmen müssen
Du willst, dass jedes neue Audit-Event auch den laufenden Zähler des Mandanten erhöht. Als zwei separate Aufrufe ausgeführt, beschädigt jeder Fehler dazwischen deine Daten:
PutItemfür das neueEVENT#…-Item — gelingt.UpdateItemfürADD eventCount 1— läuft in einen Timeout.
Jetzt hat das Log eine Zeile mehr, als der Zähler behauptet. Schritt 2 blind zu wiederholen, riskiert Doppelzählung; ihn nicht zu wiederholen, lässt sie inkonsistent. Es gibt keine sichere Wiederherstellung, weil die beiden Schreibvorgänge nie verknüpft waren.
Aus SQL kommend würdest du beide in BEGIN … COMMIT einbetten. DynamoDBs Antwort
ist eine einzige transaktionale Anfrage, die beide Schreibvorgänge zusammen
trägt.
Wie TransactWriteItems funktioniert
Laut dem
AWS Developer Guide
gruppiert TransactWriteItems „bis zu 100 Schreibaktionen in einer einzigen
Alles-oder-nichts-Operation", die bis zu 100 unterschiedliche Items adressieren,
und „die aggregierte Größe der Items in der Transaktion darf 4 MB nicht
überschreiten." Die Aktionen werden
atomar abgeschlossen — alle gelingen oder keine.
Du kannst vier Aktionstypen in einer Transaktion mischen:
Put— ein Item erstellen oder ersetzen.Update— Attribute bearbeiten (inklusiveADDfür unseren Zähler).Delete— ein Item per Key entfernen.ConditionCheck— eine Bedingung an einem Item prüfen, das du nicht anderweitig schreibst (z. B. „dieser Mandant ist noch aktiv").
Zwei weitere Regeln beißen in der Praxis. Erstens verbrauchen Transaktionen die doppelte Kapazität der äquivalenten nicht-transaktionalen Schreibvorgänge — DynamoDB führt eine Vorbereitungs- und eine Commit-Phase aus. Zweitens kannst du dasselbe Item nicht zweimal adressieren in einer Transaktion, und Transaktionen können nicht gegen Indizes ausgeführt werden.
Ein durchgerechnetes Beispiel: anhängen + zählen, atomar
Zurück zum Audit-Log. Ein Event für Mandant acme anzuhängen und seinen Zähler zu
erhöhen ist eine Transaktion mit zwei Aktionen:
| action | item | effect | |
|---|---|---|---|
| Put | TENANT#acme | EVENT#2026-06-24T09:14Z#a1 | write the new audit row |
| Update | TENANT#acme | COUNTER | ADD eventCount 1 |
Wenn die Bedingung einer der Aktionen fehlschlägt — etwa ein ConditionCheck, dass
der Mandant nicht gesperrt ist —, wird die gesamte Anfrage mit einer
TransactionCanceledException abgebrochen und keiner der Schreibvorgänge
geschieht. Log und Zähler können nie auseinanderlaufen.
Die ConditionExpression an jeder Aktion ist der Hebel. Um zu prüfen, dass die
Event-Zeile noch nicht existiert (damit ein Retry sie nicht dupliziert) und der
Mandant aktiv ist, komponierst du Bedingungen wie attribute_not_exists(SK) am
Put und status = :active als ConditionCheck.
Baue und kopiere diese typisierten Bedingungsausdrücke im
DynamoDB Expression Builder, statt
ExpressionAttributeNames und :val-Platzhalter von Hand zusammenzusetzen — der
Conditional-Write-Modus erzeugt genau die Form, die TransactWriteItems will.
Für sichere Retries bei einer wackeligen Verbindung hänge ein Client Token an:
Ein wiederholtes TransactWriteItems mit demselben Token innerhalb von 10 Minuten
gibt Erfolg zurück, ohne die Schreibvorgänge erneut anzuwenden
(Idempotenz).
In DynoTable umsetzen
DynoTable verwendet Transaktionen unter der Haube für seine eigenen
Schreibvorgänge: Wenn du mehrere Item-Änderungen vormerkst und committest, sendet
es sie als TransactWriteItems mit Optimistic-Locking-Bedingungsausdrücken,
sodass dein Bündel an Änderungen alles oder nichts ist — du wendest eine
Mehr-Item-Änderung nie nur zur Hälfte an.
Das heißt, du kannst die Event-Zeile und den Zähler im selben vorgemerkten Bündel bearbeiten, den Diff prüfen und beide atomar committen, ohne SDK-Code zu schreiben.

Fallstricke und nächste Schritte
- Plane die doppelte Kapazität ein. Ein transaktionaler Schreibvorgang berechnet die doppelte WCU eines einfachen Schreibvorgangs — in Ordnung für das gelegentliche konsistenzkritische Paar, teuer, wenn du jeden einzelnen Schreibvorgang in eine Transaktion einbettest. Nutze es dort, wo Atomarität tatsächlich zählt.
- Behandle
TransactionCanceledExceptionexplizit. Sie wird für eine fehlgeschlagene Bedingung oder einen Konflikt mit einer anderen laufenden Transaktion auf denselben Items zurückgegeben. Die Abbruchgründe sagen dir, welche Aktion fehlgeschlagen ist — inspiziere sie, wiederhole nicht blind. - Stream-Records sind nicht transaktionsbewusst. Änderungen aus einer Transaktion propagieren nach und nach zu Streams und können sich mit anderen verschränken; Consumer können keine Atomarität oder Reihenfolge annehmen — siehe DynamoDB Streams.
- Nicht für Zähler mit hohem Durchsatz. Ein einzelner heißer Zähler unter schwerer gleichzeitiger transaktionaler Last wird gedrosselt; dafür schau dir atomare Zähler oder das Sharding des Zählers an.
Transaktionen sind das Werkzeug für „diese Schreibvorgänge müssen übereinstimmen". Sobald Events konsistent landen, ist die nächste Sorge, auf sie zu reagieren — das sind DynamoDB Streams.
DynoTable herunterladen, um Mehr-Item-Änderungen vorzumerken und sie als eine einzige Transaktion gegen deine eigene Tabelle zu committen.


