DynamoDB TransactWriteItems di Node.js (AWS SDK v3)

TransactWriteItemsCommand yang berhasil nyaris tidak memberi tahu apa pun: tanpa item, tanpa atribut, responsnya kosong. Segala yang Anda butuhkan ada di exception-nya, jadi di SDK v3 blok catch di bawah inilah permukaan API yang sesungguhnya, dan ada gunanya tahu persis apa yang mendarat di sana. (Untuk menentukan kapan transaksi memang panggilan yang tepat, lihat transaksi DynamoDB.)

Kode

import {DynamoDBClient, TransactWriteItemsCommand} from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({region: 'us-east-1'});

// Move one award between two songs — atomically. If the first song has no
// award to give, NEITHER update happens.
const command = new TransactWriteItemsCommand({
  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'}}
      }
    }
  ]
});

try {
  await client.send(command);
  console.log('Transaction committed');
} catch (err) {
  if (err.name === 'TransactionCanceledException') {
    // One reason per action, in TransactItems order. 'None' means that action
    // was fine — some OTHER action sank the transaction.
    const codes = (err.CancellationReasons ?? []).map((r) => r.Code);
    console.log('Transaction canceled:', codes); // e.g. ['ConditionalCheckFailed', 'None']
  } else {
    throw err;
  }
}

Penjelasan

  • TransactItems — array terurut berisi aksi Put, Update, Delete, dan ConditionCheck. Urutannya bukan urutan eksekusi (transaksinya atomik), tetapi ia adalah urutan kembalinya alasan kegagalan, dan hanya itulah alasan untuk memedulikannya. Batasnya dibahas di bawah.
  • Apa yang sebenarnya dilempar v3. Properti milik objek yang tertangkap adalah $fault, $retryable, $metadata, name, CancellationReasons, message, dan __type. Tidak ada err.code; err.name adalah string yang harus Anda pakai untuk switch, dan err.$metadata membawa httpStatusCode: 400 plus attempts: 1, yang memberi tahu Anda bahwa SDK tidak diam-diam mencoba ulang pembatalan itu untuk Anda.
  • CancellationReasons bersifat posisional dan jarang terisi penuh. Untuk transaksi di atas ia datang sebagai [{"Code":"ConditionalCheckFailed","Message":"The conditional request failed"},{"Code":"None"}]. Entri None sama sekali tidak punya properti Message, jadi err.CancellationReasons.map((r) => r.Message.trim()) melempar error di dalam error handler Anda justru pada aksi-aksi yang berhasil.
  • ReturnValuesOnConditionCheckFailure: 'ALL_OLD' menambahkan sebuah Item ke alasan aksi tersebut, di depan Code dan Message, dalam DynamoDB JSON mentah. Atribut item yang kalah kembali secara cuma-cuma; alternatifnya adalah GetItem susulan setelah Anda telanjur kalah balapan.
  • Pemeriksaan err.name punya satu lubang, dan ada gunanya tahu yang mana. Arahkan dua aksi ke item yang sama dan DynamoDB menjawab ValidationException dengan pesan Transaction request cannot include multiple operations on one item, dan tanpa CancellationReasons sama sekali, karena tidak ada yang dicoba. Cabang else { throw err } di atas melempar ulang error itu. Itu perilaku yang benar, bukan bug, tetapi artinya kesalahan struktural tidak pernah sampai ke logging pembatalan Anda.
  • v3 sudah mengirim ClientRequestToken, bahkan ketika Anda menghilangkannya. Menangkap body terserialisasi memperlihatkan UUID baru di jalur transport, dan dua panggilan send() atas objek command yang sama berangkat dengan dua token berbeda. Jadi token itu melindungi satu panggilan yang sedang berjalan, bukan loop retry Anda sendiri: catch, kirim ulang, dan Anda punya token baru tanpa idempotensi. Sediakan token Anda sendiri kalau percobaan ulangnya bisa melintasi batas proses. Pakai ulang token itu dengan satu parameter yang diubah dan Anda mendapat IdempotentParameterMismatch alih-alih penerapan ganda yang senyap.
  • Hanya satu kode lain yang butuh jalur kode tersendiri. TransactionConflict berarti transaksi lain sedang memegang salah satu item Anda, jadi percobaan ulang dengan backoff adalah respons yang tepat — sesuatu yang tidak pernah tepat untuk ConditionalCheckFailed. Sisanya diuraikan di halaman TransactionCanceledException.
  • Biaya — setiap item dalam sebuah transaksi ditulis dua kali di baliknya (prepare, lalu commit), jadi anggarkan kira-kira 2× write capacity dari penulisan biasa. Sebuah penulisan bersyarat satu item memberi Anda atomisitas pada satu item dengan separuh biaya itu.

Batas mana yang Anda tabrak lebih dulu

Batas 100 aksi dan batas 4 MB saling bebas, dan yang berbasis byte itulah yang mengejutkan orang: seratus penambahan counter bukan apa-apa, sementara selusin item gemuk bisa menghabiskan agregatnya sendirian. Ukur satu item representatif dengan kalkulator ukuran item DynamoDB sebelum Anda memutuskan berapa banyak aksi yang di-batch. Untuk membaca item yang akan disentuh sebuah aksi sementara Anda masih menulis kondisinya, unduh DynoTable.

Contoh terkait

Referensi

Terakhir diverifikasi 2026-07-28 terhadap dokumentasi resmi AWS yang ditautkan di atas.

Bekerja dengan DynamoDB tanpa Console

Klien desktop DynamoDB yang cepat dan menjalankan SQL sungguhan yang tidak bisa dijalankan DynamoDB — JOINs, GROUP BY, agregasi — dengan editing visual dan agen AI pada kunci Bedrock milik Anda sendiri.

Uji coba gratis 30 hari, tanpa kartu kredit — lalu paket Free tanpa batas waktu.