Tratamento de concorrência na Java Persistence API - JPA

4 respostas
dreampeppers99

Gostaria de saber como implementar : pessimistic | optimistic lock no JPA.
Penso que tudo se esclarecerá melhor com um exemplo:

Num cenario com três entidades - Produto {id, descricao, preco, quantidade} , ItemVenda {id, produto, preco, quantidade} e Venda{id, List itens, data, vendedor}.

Um processo que determina uma compra é: verificar se há a quantidade de produtos e diminuir essa quantidade.

public void realizaCompra(){
tx.begin();
  for (ItemVenda item : venda.getItensVendas()){
      Produto produtoDoBanco  = em.find(Produto.class,item.getProduto().getId());
      if (produtoDoBanco.getQuantidade() < item.getProduto().getQuantidade()){
            throw new NaoHaEstoqueException("não há itens para essa venda");
      } else {
            produtoDoBanco.diminuirUnidades(item.getProduto().getQuantidade());
            em.persist(produtoDoBanco);
      }
      
  }
  em.persist(venda);
tx.commit();
}

Melhorando minha pergunta... qual tipo de lock eu deveria usar? (ou um para cada...?)

No momento em que estou lendo a quantidade de produtos que há no estoque, ninguém deveria ser capaz de alterar esse valor ... se não estiver claro ... tentarei utilizar outras palavras. :)

[Consegui resolver e até públiquei um post sobre o assunto (pouco explorado) - concorrência na JPA - http://archsofty.blogspot.com/2009/10/jpa-lock-otimista-e-pessimista.html ]

4 Respostas

K

Amigo,

Tente ver algo sobre a anotação “@Version”, to sem tempo agora pra te dar um exemplo de como usa-la, mas deve ter vários tutos pela internet, ou a própria documentação.

Abraços!

G

Minha sugestão é de fazer um lock otimista.

No seu método de negócio eu faria um refresh do objeto na base fazendo um lock no mesmo. Então nesse momento valido a quantidade lançando exception caso não houver mais produtos disponíveis; depois calculo a nova quantidade, salvo na base e libero o lock.

Usei essa mesma metodologia quando implementei o sistema de vendas de uma grande telecom aí. Funcionou muito bem.

Isso te ajuda? Abraços

G

Complementando...

public void realizaCompra(){
    tx.begin(); // você usa CMT ou BMP?

    for (ItemVenda item : venda.getItensVendas()){
        // carrega e efetua lock, libera após o transaction.commit ou transaction.rollback
        Produto produtoDoBanco  = em.find(Produto.class,item.getProduto().getId());
        em.lock(produtoDoBanco, LockMode.WRITE);

        if (produtoDoBanco.getQuantidade() < item.getProduto().getQuantidade()){
            // deu erro, o JTA fará rollback
            throw new NaoHaEstoqueException("não há itens para essa venda");
        } else {
            produtoDoBanco.diminuirUnidades(item.getProduto().getQuantidade());
        }
    }

    em.merge(venda); // salva o produto

    tx.commit(); // quando fizer commit o lock é liberado
}
dreampeppers99

Obrigado por todas as dicas, a partir dai ficou mais fácil pesquisar… até ousei a escrever algo sobre concorrência na JPA - http://archsofty.blogspot.com/2009/10/jpa-lock-otimista-e-pessimista.html

Criado 24 de outubro de 2009
Ultima resposta 29 de out. de 2009
Respostas 4
Participantes 3