MySQLやOracleでお馴染みのトランザクションがAWS DynamoDBでも実装されました。 今回はDynamoDBのトランザクションを使ってみようと思います。
制約事項などもありますので、細かい部分はAWSの公式サイトをチェックしてください。 当ブログでは使い方に重点を置いて紹介したいと思います。
流れ
Lambda(Node.js)からDynamoDBへ処理を投げて、トランクションの動きを確認してみます。
シチュエーションとしてゲームのプレイヤーがアイテムを購入するシーンを想定してみます。 所持金やアイテムを保持するプレイヤーテーブルと、在庫管理のアイテムテーブルを用意します。
データの準備
DynamoDBへデータを用意します。 プレイヤーテーブル(test_players)と、アイテムテーブル(test_items)を用意します。
playerIdが主キーです。
itemIdが主キーです。 itemCだけavailable=true(在庫有り)にしてあります。
この後、MarioにitemCを購入してもらいます。
Lambdaの用意
node.jsのLambdaを作成してください。
テンプレートを選択する所など、色々設定する場所がありますが、 後で削除するのでnode.jsであればどれを選んでも大丈夫です。
アクション>関数のエクスポート を選択してLambdaのソースコードをダウンロードします。
「デプロイパッケージのダウンロード」を押すとダウンロードが始まります。
ダウンロードしたファイルを適当な場所へ解凍し、 コマンドプロンプト(windowsの場合)かterminal(macの場合)を開いて、 解凍したフォルダへ移動してください。
cd xxxxx(解凍先)
npmを使いAWS SDKをダウンロードします。 npmがインストールされていない人は別途インストールしておいてください。
npm install aws-sdk
下記ようなindex.jsとnode_modulesのある状態になったと思います。
次にindex.jsを編集してトランザクション処理を書いていきます
console.log('Loading function'); var AWS = require('aws-sdk'); var dynamoDb = new AWS.DynamoDB(); exports.handler = async (event, context) => { var data = await dynamoDb.transactWriteItems({ TransactItems: [ { Update: { TableName: 'test_items', Key: { itemId: { S: 'itemC' } }, ConditionExpression: 'available = :true', UpdateExpression: 'set available = :false, ' + 'ownedBy = :player', ExpressionAttributeValues: { ':true': { BOOL: true }, ':false': { BOOL: false }, ':player': { S: 'Mario' } } } }, { Update: { TableName: 'test_players', Key: { playerId: { S: 'Mario' } }, ConditionExpression: 'coins >= :price', UpdateExpression: 'set coins = coins - :price, ' + 'inventory = list_append(inventory, :items)', ExpressionAttributeValues: { ':items': { L: [{ S: 'itemC' }] }, ':price': { N: '30' } } } } ] }).promise(); return `Successfully`; };
test_itemsテーブルとtest_playersテーブルを同時に更新しに行っています。 アイテムテーブルの有効なアイテム(available=true)を無効へ(available=false)変更します。 同時にプレイヤーテーブルのMarioのコインを30減らします。
出来上がったらindex.jaとnode_modulesをzipへ圧縮します。
Lambdaへアップロード
zipファイルをLambdaへアップロードし、テストで実行してみましょう。
実行結果にSuccessfullyと出れば成功です。
ValidationErrorが出てしまった場合は、更新に失敗しています。
errorMessageの後ろの方に[ValidationError]と出ていた場合は1つめのUpdateが失敗しています。 [None, ValidationError]と出ていた場合は2つめのUpdateが失敗しています。 項目の型(ListかNumberかなど)を確認してみてください。
成功後の各テーブルを見てみましょう。
プレイヤーテーブルではMarioのcoinsが30減って、inventoryに1つ増えているのが確認できます。
アイテムテーブルでは、itemCが無効(available=false)でMarioによって更新された状態になっています。
最後に
今回は正常系の紹介をしたので、あまりトランザクションの恩恵は体感できなかったかもしれません。 実行した所で[None, ValidationError]が出た方は2つめまで実行したのに、 1つめがロールバックされているのを体験できたかもしれませんが。
まだまだ実装されたばかりのトランザクション機能ですが、 機会があれば掘り下げてお伝えしていきたいと思います。