AWS SDK v2のDynamoDB(Enhanced DynamoDB)について調べた

f:id:akagoma:20211116173834p:plain

はじめに

今のプロジェクトでは、AWS SDK v1を採用している。

AWS SDK v1の開発が徐々に止まりつつあり、v2へ移行できるかどうかをそろそろ確認しておこうと重い腰を上げた。

どうせなら、クソ設計(自分が開発していない範囲)も直しておきたいので、AWSの利用箇所の設計見直しと、v2が技術的に問題なく使えるかを調査したので、そのまとめをする。

バージョン

更新が多いので、2.17.61にて調査した。

  • software.amazon.awssdk.dynamodb-enhanced:2.17.61
  • software.amazon.awssdk.dynamodb:2.17.61

サンプルプロジェクト全体像

  1. ユーザー登録をして付箋(ノート)を書き込むアプリ
  2. 登録なしでも付箋は登録することができる

※業務の実装を載せるわけにいかないので、ブログ用にプロジェクトを作り直している。

※面倒臭いので、デモアプリは徐々に完成させる。

f:id:akagoma:20211115172133p:plain

github.com

v1との違い

v1との違い①:@DynamoDBTableが無い

v1では、@DynamoDBTableアノテーションをEntityクラスに指定し、Entityにテーブル名を定義することができた。しかしv2では@DynamoDBTableアノテーションが削除されている。

代わりに@DynamoDbBeanを付与し、EntityがDynamoDBのBeanであることを定義する。だが、このアノテーションはテーブル名を指定できない。

テーブル名の指定方法は、AWSが提供するサンプルでは、テーブル名を直接Stringで指定したりしているが、個人的に「キーの情報はEntity内でアノテーションで定義しているのに、テーブル名はアノテーションで定義できないってどういうこと?」となったので半ば強引ではあるが、javax.persistenceの@Tableのアノテーションを使い、各Entityで指定できるようにしている。(→Note.java

無理矢理感は拭えないが、EntityインターフェースにgetTable()メソッドを定義し、全Entityクラスでそれを実装するよりは遥かに良いと考えた。(テーブル名をマジックナンバーで使うのは論外。)

v1との違い②:@DynamoDBHashKey/@DynamoDBRangeKeyが変わった

v1では、@DynamoDBHashKey/@DynamoDBRangeKeyアノテーションをEntityの変数に指定することで変数とカラムを紐付けていた。しかしv2ではどちらのアノテーションも削除されている。

v2からはGetterに@DynamoDbPartitationKey/@DynamoDbSortKeyを付与するように変わった。なぜ、Getterに付与するようになったのか理由はよくわからないが、個人的には大変ガッカリしている。

なぜなら、全てのEntityクラスに自作のGetterを作成しなくてはならなくなったからだ。lombokのgetterの恩恵を使えなくなったのが非常に痛い。

パーティションキー/ソートキー以外は@DynamoDbAttributeを付与するが、これもGetterに付与するように変わった。

サンプルプロジェクトでは使っていないが、@DynamoDBIndexHashKey/@DynamoDBIndexRangeKeyも@DynamoDbSecondaryPartitationKey/@DynamoDbSecondarySortKeyに変わった。

v2(Enhanced DynamoDB)の使い方

個人的に、Enhanced DynamoDBの利用を推奨する。

理由は、Enhanced DynamoDBは文字通り、通常のDynamoDBを拡張して使いやすくなっているクラスであり、正直通常のDynamoDBを使う旨味が分からなかった。

テーブル作成

一瞬で作成可能。テーブル作成をアプリからやるシーケンスがあまり想像できないが、Entityクラスにテーブルの情報を全て定義しておくとこのように一瞬で作ることができる。

デフォルトから設定変更する場合も、設定の要求クラスを作成するだけで良い。

テーブル削除

作成と同様、一瞬で削除可能。

EntityのPut/Update

Entityに対する操作は基本的に共通で、dynamoDBClientからTableを作成し、Tableに対して操作をするという流れになる。

PutとUpdateは同じように見えるが、以下の点で違う。

  • PUT:入力で指定されていない属性がある場合削除される。
  • UPDATE:入力で指定した項目属性のみを変更する。

EntityのGet/Scan

Getの場合はKey.builder()を利用し、PartitationKey/SortKey指定してEntityを取得する。

EntityのDelete

DeleteはGet/Scanの時と同様にKey.builder()を利用したPartitationKey/SortKey指定での削除の他に、Entityクラスを指定した削除も可能。ただ内部的にPartitationKey/SortKeyしか使われていないのか、全てが合致するレコードを消しているのかはまだ調査できていない。

DynamoDB Transactionを利用した書き込み

DynamoDB Transactionを利用すると、複数テーブルへの複数データを1つのトランザクションで書き込むことができる。同時に書き込めるEntityの数に上限があり25個までとなっている。

Springbootで使う場合のベターな設計

個人的に考える、DynamoDBをSpringbootで使う場合のベターな設計としてはこんな感じになった。

  • AbstractDynamoDB抽象クラスを作成し、総称型として扱うEntityのクラスを持ち、DynamoDBを使った必要な操作を定義しておく。

  • @Controller→@Service→@Repositoryのルートでアクセスする。@Serviceは@Repositoryの実装を知る必要は無いので、インターフェースクラスを作成する。

  • 実装クラスでは、インターフェースクラスを実現し、AbstractDynamoDBクラスを継承する。

感想

v2に難なく移行することはできそう。

現行のクソ設計ではDynamoDBのTransactionを考慮していないので、そこを重点的に調査した。Transactionを利用したGetもできるのだが、どうも使い所が思いつかなかったので、今回は調査対象外とした。

AWS SDK v2の日本語情報が全然無いので、英語読めない人は苦労しそう。

その他参考になるサイト

github.com

Copyright (C) 2021 akagoma. All Rights Reserved.