Python'da (boto3) DynamoDB TransactWriteItems

İşlemler, boto3'ün iki API'sinin en sert ayrıştığı yerlerden biridir: transact_write_items yalnızca düşük düzeyli istemcide bulunur, dolayısıyla Table'dan aldığınız yerel Python türleri rahatlığı burada yoktur. Ve işlem başarısız olduğunda, ihtiyacınız olan şey çoğu boto3 kodunun hiç bakmadığı bir istisna köşesindedir. (Bir işlemin size ne kazandırdığı her SDK'da aynıdır.)

Kod

import boto3

client = boto3.client("dynamodb")

# Move one award between two songs — atomically. If the first song has no
# award to give, NEITHER update happens.
try:
    client.transact_write_items(
        TransactItems=[
            {
                "Update": {
                    "TableName": "Music",
                    "Key": {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
                    "UpdateExpression": "SET #upd0 = #upd0 - :one",
                    "ConditionExpression": "#upd0 >= :one",
                    "ExpressionAttributeNames": {"#upd0": "Awards"},
                    "ExpressionAttributeValues": {":one": {"N": "1"}},
                }
            },
            {
                "Update": {
                    "TableName": "Music",
                    "Key": {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "A Mis Abuelos"}},
                    "UpdateExpression": "SET #upd0 = if_not_exists(#upd0, :zero) + :one",
                    "ExpressionAttributeNames": {"#upd0": "Awards"},
                    "ExpressionAttributeValues": {":one": {"N": "1"}, ":zero": {"N": "0"}},
                }
            },
        ]
    )
    print("Transaction committed")
except client.exceptions.TransactionCanceledException as e:
    # One reason per action, in TransactItems order. Code "None" means that
    # action was fine — some OTHER action sank the transaction.
    codes = [reason["Code"] for reason in e.response["CancellationReasons"]]
    print(f"Transaction canceled: {codes}")  # e.g. ['ConditionalCheckFailed', 'None']

Açıklama

  • TransactItemsPut, Update, Delete ve ConditionCheck sözlüklerinden oluşan bir liste; her değer, istisnasız, DynamoDB JSON biçiminde. Tipli biçimin isteğe bağlı olmadığı tek boto3 çağrısı budur ve bu sayfanın sonundaki bölümün var olma nedeni de odur. Üst sınırlar CLI sayfasındadır.
  • CancellationReasons, Error'ın içinde değildir. botocore, modellenmiş hata alanlarını yanıt sözlüğünün en üstüne çıkarır; dolayısıyla yakalanan istisna, CancellationReasons, Error, Message ve ResponseMetadata anahtarlarını yan yana taşıyan bir e.response getirir. Onu e.response["Error"] altında aramak hiçbir şey bulmaz ve e.response["Error"] yalnızca özet kodu ve mesajı tutar.
  • None girdilerinde "Message" yoktur — başarılı bir eylemin nedeni, tek anahtarlı {"Code": "None"} sözlüğüdür; dolayısıyla doğal görünen [r["Message"] for r in reasons], tam da işe yaramış eylemlerde KeyError: 'Message' fırlatır. r.get("Message") kullanın.
  • Üretilmiş bir istisna sınıfı — botocore, client.exceptions.TransactionCanceledException'ı hizmet modelinden çalışma zamanında kurar; istemci örneğine bağlı olmasının ve onu from botocore.exceptions import ... diye içe aktaramamanızın nedeni budur. Kapsamında istemci olmayan bir yardımcıda botocore.exceptions.ClientError'ı yakalayın ve e.response["Error"]["Code"] üzerinden dallanın; üretilmiş sınıf onun bir alt sınıfıdır.
  • Yapısal hatalar iptal olarak gelmez, dolayısıyla parçacıktaki except yan tümcesi onları hiç görmez. Aynı öğeye yönelmiş iki eylem, kodu ValidationException olan ve e.response'unda CancellationReasons anahtarı bulunmayan çıplak bir ClientError fırlatır, çünkü işlem hiçbir eylem çalışmadan önce reddedilmiştir. Bunların da aynı bağlamla günlüklenmesini istiyorsanız dış kenarda ClientError yakalayın.
  • Bir eylemdeki ReturnValuesOnConditionCheckFailure: "ALL_OLD", kaybeden öğeyi o eylemin nedeninde bir Item anahtarı altında, DynamoDB JSON biçiminde koyar; böylece yarışı çoktan kaybettikten sonra bir de get_item yapmanıza gerek kalmaz.
  • ClientRequestToken'ı boto3 sizin için doldurur. Kabloda yakalandığı üzere, birbirinin aynı iki transact_write_items çağrısı iki farklı UUID ile çıktı; yani belirteç tek bir çağrıyı kapsar, kendi yakala-ve-yeniden-dene döngünüzü değil. Yeniden deneme süreçten uzun yaşayabiliyorsa sabit bir tanesini kendiniz geçin.
  • TransactionConflict'te yeniden deneyin, ConditionalCheckFailed'de asla — birincisi öğeyi bir an için başkasının tuttuğunu söyler; ikincisi ön koşulunuzun yanlış olduğunu ve bir dahaki sefere de yanlış olacağını söyler. Çoğu işleyicinin ayırması gereken tek iki kod bunlardır; tam küme TransactionCanceledException sayfasında çözümleniyor.
  • Maliyet — işlemsel bir yazma, aynı yazmanın işlem dışındaki maliyetinin kabaca iki katını faturalandırır, CLI sayfasında ölçüldüğü gibi. Yalnızca tek bir öğede atomikliğe ihtiyacınız varsa, bir koşullu yazma bunu yarı fiyatına verir.

Bunun kaynak API'si sürümü yoktur

boto3.resource("dynamodb").Table(...)'ın transact_write_items özniteliği yoktur; yalnızca resource.meta.client'ın vardır. Dolayısıyla Table ve yerel Python türlerinde karar kılmış bir kod tabanı, işlemleri için tipli DynamoDB JSON'una geri dönmek ya da boto3.dynamodb.types.TypeSerializer ile elle serileştirmek zorundadır:

from boto3.dynamodb.types import TypeSerializer

serialize = TypeSerializer().serialize
values = {k: serialize(v) for k, v in {":one": 1, ":zero": 0}.items()}

TypeSerializer, kaynak API'siyle aynı kuralları uygular; yani float'ı reddeder ve kesirli her şey için decimal.Decimal bekler. DynamoDB JSON dönüştürücüsü, bir betiğe yalnızca bir sabit yapıştırmanız gerektiğinde aynı dönüşümü tarayıcıda yapar. Bir işlemin dokunduğu öğeleri iki biçimden birini elle yazmadan düzenlemek için DynoTable'ı indirin.

İlgili örnekler

Kaynaklar

En son 2026-07-28 tarihinde yukarıda bağlantısı verilen resmi AWS belgelerine karşı doğrulandı.

Console olmadan DynamoDB ile çalış

DynamoDB’nin çalıştıramadığı gerçek SQL’i çalıştıran hızlı bir DynamoDB masaüstü istemcisi — JOINs, GROUP BY, toplamalar — görsel düzenleme ve kendi Bedrock anahtarların üzerinde bir yapay zekâ aracısıyla.

30 günlük ücretsiz deneme, kredi kartı yok — ardından süre sınırı olmayan Ücretsiz plan.