DynamoDBにboto3でトランザクションな書き込み

DynamoDBはトランザクションをサポートしている。とはいえ基本的に原子性を求められるようなユースケースでは使わないほうがよいと思うけれど、できると幅が広がるので、覚えておいて損はない。ということで、boto3での使い方のメモ書き。

目次

やること

以下のようなテーブルを作る。

  • テーブル名 transact-test
  • パーティションキー user_id
  • user_idがhoge、user_nameがfugaさんのアイテムを投入

このtransact-testテーブルに、以下のような処理を行う。

  • user_id=hogeのuser_nameをafterに変更する
  • user_id=add を追加する
  • 両方の処理が成功して初めて処理が反映される

更新と追加、両方の処理ができて初めて一つの処理とみなす、というテスト。

サンプルコード

以下のようなソースコードを書く。

"""boto3のtransact_write_items()を試すテストコード"""

import boto3

client_dynamo = boto3.client('dynamodb', region_name='ap-northeast-1')

TABLE_NAME = 'transact-test'


def dict2dynamoformat(orig_dict):
    """辞書配列をDynamoDB用に変換する"""
    ret_dict = {}
    for k, v in orig_dict.items():
        print(k,v)
        ret_dict[k] = _to_dynamo_format(v)
    return ret_dict

def _to_dynamo_format(v):
    """dict2dynamoformatの変換部分でSet系の型は未対応"""
    if type(v) is str:
        return {'S': v}
    if type(v) is int:
        return {'N': str(v)}
    if type(v) is bool:
        return {'BOOL': v}
    if type(v) is list:
        return {'L': [_to_dynamo_format(a) for a in v]}
    if type(v) is dict:
        return {'M': dict2dynamoformat(v)}


if __name__ == '__main__':
    item = {
        'user_id': 'add',
        'user_name': 'add_test',
    }

    item4dynamo = dict2dynamoformat(item)
    client_dynamo.transact_write_items(
        TransactItems=[
            {
                'Put': {
                    'TableName': TABLE_NAME,
                    'Item': item4dynamo,
                },
            },
            {
                'Update': {
                    'TableName': TABLE_NAME,
                    'Key': {
                        'user_id': {'S': 'hoge'}
                    },
                    'UpdateExpression': 'SET user_name = :un',
                    'ExpressionAttributeValues': {
                        ':un': {'S': 'after'}
                    }
                }
            }
        ]
    )

client_dynamo.transact_write_items()が書き換えの処理内容。使い方は「DynamoDB — Boto 3 Docs 1.9.121 documentation」を見るのが一番。boto3でDynamoDB使う時は、だいたいresourceを使うと思うのだが、transact_write_itemsを使いたいのであれば、抽象レベルの低いclientを用いる。そのうち対応されるのかなぁ。

dict2dynamoformatは、書き込みアイテムの配列が、普通の辞書配列をそのまんま突っ込んではダメなので、DynamoDBに登録できるように変換するための関数。Setな型には対応していない。自分が使ってないから……。

実行すると、ちゃんと書き換えが行われる。

実行結果

片方でも失敗すると、どちらの処理も反映されない。

transact_write_items()なんかないと怒られた時

ひょっとすると、transact_write_ites()なんかないよと怒られるかもしれない。これはboto3が古いです。更新しましょう。

……ローカルなら更新しましょうでよいのだけれど、Lambdaで使おうとしてこれが出ると、新しいboto3を別環境でzip化して入れるという謎の工程が入ることになってしまってテンション下がる。そのうち対応されるのでしょうか。。。

参考記事

ありがとうございましたm(_ _)m

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次