View a markdown version of this page

DynamoDB e bloqueio positivo com número de versão - Amazon DynamoDB

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 para 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.

nota

Quando você salva um item que ainda não existe na tabela, o valor da propriedade de versão determina como o DynamoDBMapper constrói a operação de gravação:

  • Se a propriedade de versão for null, o DynamoDBMapper tratará a operação como uma inserção de um novo item. Ele adicionará uma condição de que o atributo de versão ainda não existe e definirá a versão armazenada como 1. O salvamento será bem-sucedido somente se ainda não existir um item com a mesma chave.

  • Se a propriedade de versão estiver definida com qualquer valor (por exemplo, 0, 1 ou 5), o DynamoDBMapper tratará a operação como uma atualização de um item existente. Ele adicionará uma condição de que a versão armazenada seja igual àquele valor e, em seguida, a incrementará. Se o item ainda não existir, a condição falhará e a operação de salvamento lançará uma ConditionalCheckFailedException.

Para inserir um novo item, deixe a propriedade de versão como null; para atualizar um item existente, defina a propriedade de versão com o valor lido mais recentemente. Você não precisa inspecionar o valor da versão para distinguir uma inserção de uma atualização. O DynamoDBMapperusa a distinção entre null e valor definido para tomar essa decisão. A propriedade de versão deve ser de um tipo anulável (por exemplo, Long em vez de long) para que o DynamoDBMapper possa detectar quando a versão não foi definida.

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 com DynamoDBSaveExpression 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 classe DynamoDBMapper incrementa o número de versão automaticamente.

  • delete: o método delete usa um objeto como parâmetro, e DynamoDBMapper realiza uma verificação de versão antes de excluir o item. A verificação da versão pode ser desabilitada se DynamoDBMapperConfig.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 classe DynamoDBMapper 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 classe DynamoDBMapper incrementa o número de versão automaticamente.

    • Delete: o DynamoDBMapper 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ções ConditionCheck. Uma SdkClientException será lançada quando um item ConditionCheck 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));