DynamoDB e bloqueio positivo com número de versão
O bloqueio positivo é uma estratégia para garantir que o item no lado do cliente que você está atualizando (ou excluindo) seja o mesmo que o item no Amazon DynamoDB. Se você usar essa estratégia, suas gravações de banco de dados serão protegidas contra substituição pelas gravações de outros e vice-versa.
Com o bloqueio positivo, cada item tem um atributo que serve como um número de versão. Se você recuperar um item de uma tabela, o aplicativo registrará o número da versão desse item. Você poderá atualizar o item somente se o número de versão no lado do servidor não tiver sido alterado. Se há uma incompatibilidade de versão, isso significa que alguém modificou o item antes de você. A tentativa de atualização falha, porque você tem uma versão obsoleta do item. Se isso acontecer, basta tentar novamente ao recuperar o item e tentar atualizá-lo. O bloqueio positivo impede que você substitua acidentalmente as alterações que foram feitas por outros. Também impede que outros substituam acidentalmente suas alterações.
Embora seja possível implementar a própria estratégia de bloqueio positivo, o AWS SDK for Java oferece a anotação @DynamoDBVersionAttribute
. Na classe de mapeamento da sua tabela, você designa uma propriedade para armazenar o número da versão e a marca usando essa anotação. Quando um objeto é salvo, o item correspondente na tabela do DynamoDB terá um atributo que armazena o número da versão. O DynamoDBMapper
atribui um número de versão quando você salvar o objeto pela primeira vez e incrementa automaticamente o número da versão sempre que você atualiza o item. Suas solicitações de atualização ou exclusão só serão bem-sucedidas se a versão do objeto no lado do cliente corresponder ao número de versão correspondente do item na tabela do DynamoDB.
ConditionalCheckFailedException
será lançada se:
-
Você usar bloqueio positivo com
@DynamoDBVersionAttribute
e o valor de versão no servidor for diferente do valor no lado do cliente. -
Você especificar suas próprias restrições condicionais ao salvar dados usando
DynamoDBMapper
comDynamoDBSaveExpression
e ocorrer falha nessas restrições.
nota
-
As tabelas globais do DynamoDB usam uma reconciliação “último gravador ganha” entre as atualizações simultâneas. Se você usa tabelas globais, a política de último gravador ganha. Portanto, neste caso, a estratégia de bloqueio não funciona como esperado.
-
As operações de gravação transacional
DynamoDBMapper
não são compatíveis com expressões de condição e anotação@DynamoDBVersionAttribute
no mesmo objeto. Se um objeto em uma gravação transacional for anotado com@DynamoDBVersionAttribute
e também tiver uma expressão de condição, a SdkClientException será lançada.
Por exemplo, o código Java a seguir define uma classe CatalogItem
que tem várias propriedades. A propriedade Version
está marcada com a anotação @DynamoDBVersionAttribute
.
exemplo
@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;} }
Você pode aplicar a anotação @DynamoDBVersionAttribute
a tipos anuláveis fornecidos pelas classes wrapper primitivas que fornecem um tipo que permite valor nulo, como Long
e Integer
.
O bloqueio positivo tem o seguinte impacto sobre estes métodos DynamoDBMapper
:
-
save
: para um novo item,DynamoDBMapper
atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação de salvamento será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponderem. A classeDynamoDBMapper
incrementa o número de versão automaticamente. -
delete
: o métododelete
usa um objeto como parâmetro, eDynamoDBMapper
realiza uma verificação de versão antes de excluir o item. A verificação da versão pode ser desabilitada seDynamoDBMapperConfig.SaveBehavior.CLOBBER
for especificado na solicitação.A implementação interna do bloqueio positivo em
DynamoDBMapper
usa o suporte a atualizações e exclusões condicionais fornecido pelo DynamoDB. -
transactionWrite
—-
Put
: para um novo item,DynamoDBMapper
atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Put será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classeDynamoDBMapper
incrementa o número de versão automaticamente. -
Update
: para um novo item,DynamoDBMapper
atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Update será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classeDynamoDBMapper
incrementa o número de versão automaticamente. -
Delete
: oDynamoDBMapper
realiza uma verificação de versão antes de excluir o item. A operação Delete só será bem-sucedida se o número de versão no lado do cliente e no lado do servidor corresponder. -
ConditionCheck
: a anotação@DynamoDBVersionAttribute
não é compatível com operaçõesConditionCheck
. Uma SdkClientException será lançada quando um itemConditionCheck
for anotado com@DynamoDBVersionAttribute
.
-
Desabilitar o bloqueio positivo
Para desabilitar o bloqueio positivo, você pode alterar o valor de enumeração DynamoDBMapperConfig.SaveBehavior
de UPDATE
para CLOBBER
. Você pode fazer isso criando uma instância de DynamoDBMapperConfig
que ignora a verificação de versão e usando essa instância para todas as suas solicitações. Para obter informações sobre DynamoDBMapperConfig.SaveBehavior
e outros parâmetros DynamoDBMapper
opcionais, consulte Definições de configuração opcionais para DynamoDBMapper .
Você também pode definir um comportamento de bloqueio somente para uma operação específica. Por exemplo, o seguinte trecho de código Java usa DynamoDBMapper
para salvar um item de catálogo. Ele especifica DynamoDBMapperConfig.SaveBehavior
adicionando o parâmetro DynamoDBMapperConfig
opcional ao método save
.
nota
O método transactionWrite não oferece suporte à configuração DynamoDBMapperConfig.SaveBehavior. A desabilitação do bloqueio positivo para transactionWrite é incompatível.
exemplo
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));