DynamoDBのトランザクション処理についてAWS CLIで検証してみた


## はじめに
業務で、DynamoDBで2つのテーブルを扱う必要がでてきたのでトランザクション処理について動作検証しました。

## DynamoDBのトランザクションについて

DynamoDBが公式に機能として提供しています。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/transactions.html

CLIの場合は、transact-write-itemsを使うことでデータ更新時のトランザクション処理を実装できるようだったので、ためしてみました。

https://docs.aws.amazon.com/cli/latest/reference/dynamodb/transact-write-items.html

https://amazon-dynamodb-labs.workshop.aws/hands-on-labs/explore-cli/cli-transactions.html

## 準備
2つのテーブルを作成
CLI用のアクセスキー取得及び設定
以下コマンドで作成テーブルが参照できることを確認

```bash
$ aws dynamodb list-tables --profile sandbox
{
    "TableNames": [
        "Test1",
        "Test2"
    ]
}
```

## 検証内容

### 1: 2つのテーブルの更新が成功する場合(新規追加)

以下コマンドを実行します。

```bash
aws dynamodb transact-write-items --profile sandbox --transact-items '[
    {
        "Put": {
            "TableName" : "Test1",
            "Item" : {
                "ID" : {"S": "001"},
                "Point" : {"S": "1"}
            }
        }
    },
    {
        "Put": {
            "TableName" : "Test2",
            "Item" : {
                "ID" : {"S": "001"},
                "TotalPoint" : {"S": "2"}
            }
        }
    }
]'
```

以下のように、テーブルにデータが追加されています。

```bash
$ aws dynamodb scan --table-name Test1 --profile sandbox
{
    "Items": [
        {
            "ID": {
                "S": "001"
            },
            "Point": {
                "S": "1"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}
```

```bash
$ aws dynamodb scan --table-name Test2 --profile sandbox
{
    "Items": [
        {
            "TotalPoint": {
                "S": "2"
            },
            "ID": {
                "S": "001"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}
```

### 2: 2つのテーブルの更新が成功する場合(更新)

先ほどのコマンドで追加した要素に対して更新してみます。
本来はUpdateを使うべきですが、Putでも同じことができるので、こちらを使用します。

```bash
aws dynamodb transact-write-items --profile sandbox --transact-items '[
    {
        "Put": {
            "TableName" : "Test1",
            "Item" : {
                "ID" : {"S": "001"},
                "Point" : {"S": "999"}
            }
        }
    },
    {
        "Put": {
            "TableName" : "Test2",
            "Item" : {
                "ID" : {"S": "001"},
                "TotalPoint" : {"S": "999"}
            }
        }
    }
]'
```

以下のように、対象IDの属性が更新されることを確認できました。

```bash
$ aws dynamodb scan --table-name Test1 --profile sandbox
{
    "Items": [
        {
            "ID": {
                "S": "001"
            },
            "Point": {
                "S": "999"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}
```

```bash
$ aws dynamodb scan --table-name Test2 --profile sandbox
{
    "Items": [
        {
            "TotalPoint": {
                "S": "999"
            },
            "ID": {
                "S": "002"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}
```

### 3: テーブルの更新に失敗する場合(テーブル名が不正)

最初のPutコマンドで存在しないテーブル(Test3)を指定してみます。

```bash
aws dynamodb transact-write-items --profile sandbox --transact-items '[
    {
        "Put": {
            "TableName" : "Test3",
            "Item" : {
                "ID" : {"S": "001"},
                "Point" : {"S": "5"}
            }
        }
    },
    {
        "Put": {
            "TableName" : "Test2",
            "Item" : {
                "ID" : {"S": "001"},
                "TotalPoint" : {"S": "100"}
            }
        }
    }
]'
```

以下のエラーが出て失敗しました。

```bash
An error occurred (ResourceNotFoundException) when calling the TransactWriteItems operation: Requested resource not found
```

また、先ほどのコマンドでそれぞれのテーブルを確認したところ、更新されていないことを確認しました。(内容が重複するので割愛)

### 4: 片方のテーブルの更新に失敗する場合(プライマリキーが不正)

次に、2つ目のPutコマンドで存在しないプライマリキーを(ID_DUMMY)を指定してみます。

```bash
aws dynamodb transact-write-items --profile sandbox --transact-items '[
    {
        "Put": {
            "TableName" : "Test1",
            "Item" : {
                "ID" : {"S": "001"},
                "Point" : {"S": "100"}
            }
        }
    },
    {
        "Put": {
            "TableName" : "Test2",
            "Item" : {
                "ID_DUMMY" : {"S": "001"},
                "TotalPoint" : {"S": "200"}
            }
        }
    }
]'
```

先ほどと同様に、以下エラーが発生しました。

```bash
An error occurred (TransactionCanceledException) when calling the TransactWriteItems operation: Transaction cancelled, please refer cancellation reasons for specific reasons [None, ValidationError]
```

また、先ほどのコマンドでそれぞれのテーブルを確認したところ、更新されていないことを確認しました。(内容が重複するので割愛)

## まとめ

DynamoDBのトランザクション処理についてCLIで検証してみました。

割と簡単に実装できそうで、業務でも十分活用できそうなことが分かったので良かったです。