DynamoDB およびバージョン番号を使用した楽観的ロック
オプティミスティックロックとは、更新 (または削除) しているクライアント側の項目と、Amazon DynamoDB の項目を確実に同じになるようにするための手段です。この方法を使用すると、データベースの書き込みは、他のユーザーの書き込みによって上書きされないように保護されます。逆の場合も同様に保護されます。
オプティミスティックロックを使用する場合、各項目には、バージョン番号として機能する属性があります。項目をテーブルから取り出すと、アプリケーションは、その項目のバージョン番号を記録します。サーバー側のバージョン番号が変更されていない場合のみ、項目を更新できます。バージョンの不一致がある場合は、前に他のユーザーによってそのアイテムが変更されたことを意味します。アイテムの古いバージョンがあるため、更新の試行は失敗します。その場合は更新をやり直します。もう一度項目を取得して、更新してください。オプティミスティックロックでは、他のユーザーが行った変更を誤って上書きできないようにします。また、お客様が行った変更を他のユーザーが誤って変更することを防ぐこともできます。
独自の楽観的ロック戦略を実装することもできますが、AWS SDK for Java には @DynamoDBVersionAttribute
アノテーションが用意されています。テーブルのマッピングクラスで、バージョン番号を保存する 1 つのプロパティを指定し、この注釈を使用してそのプロパティをマーキングします。オブジェクトを保存すると、DynamoDB テーブル内の対応する項目に、バージョン番号を格納するための属性が追加されます。DynamoDBMapper
では、最初にオブジェクトを保存したときにバージョン番号が割り当てられ、項目を更新するたびにバージョン番号が自動的にインクリメントされます。更新または削除リクエストは、クライアント側オブジェクトのバージョン番号が、DynamoDB テーブルで対応する項目のバージョン番号に一致する場合のみ成功します。
ConditionalCheckFailedException
以下の場合、 はスローされます。
-
オプティミスティックロックを
@DynamoDBVersionAttribute
と共に使用しており、サーバーのバージョンの値が、クライアント側の値とは異なる場合。 -
DynamoDBMapper
でDynamoDBSaveExpression
を使用してデータを保存するときに、独自の条件付き制約を指定し、それらの制約に障害が生じた場合。
注記
-
DynamoDB のグローバルテーブルはグローバルテーブルでは、同時更新間の「最新書き込み」の照合を行います。グローバルテーブルを使用する場合、最後に書き込まれたポリシーが採用されます。したがってこの場合、ロック戦略は想定通りに機能しません。
-
DynamoDBMapper
トランザクションの書き込みオペレーションは、同じオブジェクトでの@DynamoDBVersionAttribute
注釈と条件式をサポートしていません。トランザクション書き込み内のオブジェクトに@DynamoDBVersionAttribute
の注釈が付けられ、条件式も含まれている場合、SdkClientException がスローされます。
たとえば次の Java コードでは、複数のプロパティを持つ CatalogItem
クラスを定義しています。Version
プロパティは @DynamoDBVersionAttribute
注釈でタグ付けされています。
例
@DynamoDBTable(tableName="ProductCatalog") public class CatalogItem { private Integer id; private String title; private String ISBN; private Set<String> bookAuthors; private String someProp; private Long version; @DynamoDBHashKey(attributeName="Id") public Integer getId() { return id; } public void setId(Integer Id) { this.id = Id; } @DynamoDBAttribute(attributeName="Title") public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @DynamoDBAttribute(attributeName="ISBN") public String getISBN() { return ISBN; } public void setISBN(String ISBN) { this.ISBN = ISBN;} @DynamoDBAttribute(attributeName = "Authors") public Set<String> getBookAuthors() { return bookAuthors; } public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; } @DynamoDBIgnore public String getSomeProp() { return someProp;} public void setSomeProp(String someProp) {this.someProp = someProp;} @DynamoDBVersionAttribute public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version;} }
@DynamoDBVersionAttribute
注釈は、Long
や Integer
などの、null が許容された型を提供するプリミティブラッパークラスによって得られた、null が許容された型に適用できます。
オプティミスティックロックは、次の DynamoDBMapper
メソッドに対して次のような影響があります。
-
save
–DynamoDBMapper
は、新しい項目に対して初期バージョン番号 1 を割り当てます。項目を取得し、その項目の 1 つ以上のプロパティを更新して変更を保存する場合には、クライアント側とサーバー側のバージョン番号が一致する場合のみ、保存が成功します。DynamoDBMapper
によってバージョン番号が自動的にインクリメントされます。 -
delete
–delete
メソッドは 1 つのオブジェクトをパラメータとして指定し、項目を削除する前にDynamoDBMapper
によるバージョンチェックが実行されます。バージョンチェックは、リクエスト内でDynamoDBMapperConfig.SaveBehavior.CLOBBER
を指定して無効にすることができます。DynamoDBMapper
内のオプティミスティックロックの内部実装では、DynamoDB の条件付き更新と条件付き削除機能が使用されます。 -
transactionWrite
—-
Put
–DynamoDBMapper
は、新しい項目に対して初期バージョン番号 1 を割り当てます。項目を取得し、その項目の 1 つ以上のプロパティを更新して変更を保存する場合には、クライアント側とサーバー側のバージョン番号が一致する場合のみ、put オペレーションが成功します。DynamoDBMapper
によってバージョン番号が自動的にインクリメントされます。 -
Update
–DynamoDBMapper
は、新しい項目に対して初期バージョン番号 1 を割り当てます。項目を取得し、その項目の 1 つ以上のプロパティを更新して変更を保存する場合には、クライアント側とサーバー側のバージョン番号が一致する場合のみ、更新オペレーションが成功します。DynamoDBMapper
によってバージョン番号が自動的にインクリメントされます。 -
Delete
–DynamoDBMapper
は、項目を削除する前にバージョンチェックを実行します。削除オペレーションは、クライアント側とサーバー側のバージョン番号が一致する場合にのみ成功します。 -
ConditionCheck
–@DynamoDBVersionAttribute
アノテーションは、ConditionCheck
オペレーションではサポートされていません。ConditionCheck
項目に@DynamoDBVersionAttribute
の注釈が付いている場合、SdkClientException がスローされます。
-
楽観的ロックの無効化
オプティミスティックロックを無効にするには、DynamoDBMapperConfig.SaveBehavior
列挙値を UPDATE
から CLOBBER
に変更します。その場合は、バージョンチェックを省略する DynamoDBMapperConfig
インスタンスを作成して、そのインスタンスをすべてのリクエストで使用します。DynamoDBMapperConfig.SaveBehavior
とその他のオプションの DynamoDBMapper
パラメータの詳細については、「DynamoDBMapper のオプションの構成設定 」を参照してください。
ロック動作は、特定のオペレーションだけに設定することもできます。たとえば次の Java コードスニペットではDynamoDBMapper
を使用してカタログ項目を保存しています。オプションの DynamoDBMapperConfig.SaveBehavior
パラメータを DynamoDBMapperConfig
メソッドに追加することで、save
を指定しています。
注記
transactionWrite メソッドは、DynamoDBMapperConfig.SaveBehavior 構成をサポートしていません。transactionWrite のオプティミスティックロックの無効化はサポートされていません。
例
DynamoDBMapper mapper = new DynamoDBMapper(client); // Load a catalog item. CatalogItem item = mapper.load(CatalogItem.class, 101); item.setTitle("This is a new title for the item"); ... // Save the item. mapper.save(item, new DynamoDBMapperConfig( DynamoDBMapperConfig.SaveBehavior.CLOBBER));