Pesquisar

quinta-feira, 29 de outubro de 2009

JPA - lock otimista e pessimista, concorrência e afins

JPA - Java Persistence API

JPA é especificação para mapeamento ORM e persistência de dados inspiradíssima no famoso framework Hibernate.

A especificação JPA (1.0) já é amplamente usada e aceita na comunidade de desenvolvedores Java. Há vários provedores de implementação para o padrão ( Hibernate , EclipseLink, TopLink ...)

Um assunto pouco explorado, quando se trata de tutoriais de jpa, é sobre locks (otimista e pessimista). E é sobre esse assunto que tento escrever um pouco aqui.

Tratamento de concorrência em bancos de dados

Há basicamente três tipos de tratamento para concorrência em banco de dados:
  1. Otimista - Quando é criado mecanismos para versionar o dado, no momento em que o banco vai efetivar sua operação sua versão é checada para garantir que você está com um dado que não foi alterado.
  2. Pessimista - O banco simplesmente trava o dado e só aquele que tem a trava consegue trabalhar com os dados.
  3. Ostrich - Quando não há tratamento nenhum pra concorrência :) , ou seja, a maioria dos casos atuais.

O exemplo básico

Começaremos com os perigos do modo Ostrich de agir. Para exemplificar criaremos uma simples classe.
@Entity
public class Produto implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nome;
private double quantidade;
//getters and setters omitidos
}
Agora considere dois usuários A e B trabalhando sobre o Produto com id = 1( Nintendo Wii) ambos usuários têm o mesmo produto na tela de edição, o usuário A modifica quantidade e salva antes do usuário B, já o usuário B modifica o nome e salva depois. Note que há incosistência, o usuário A acredita (porque ele editou e salvou) que alterou a quantidade de nintendos wii, porém o usuario B (ainda com a quantidade antiga) mudou o nome e salvou o objeto. O que acontece? Depende do seu provedor de JPA, há casos em que o update só é feito para a coluna modificada mas há casos em que o objeto todo é modificado, o que causa claramente inconsistência. Escrever, escrever e escrever pode não ajudar então veja o código abaixo exemplificando esse cenário.
            Produto nintendoWiiA = em.find(Produto.class,1L);
Produto nintendoWiiB = em.find(Produto.class,1L);
/*Usuário A*/
em.getTransaction().begin();
nintendoWiiA.setQuantidade(45.0D);
em.getTransaction().commit();

/*Usuário B*/
em.getTransaction().begin();
nintendoWiiB.setNome("Nintendo WII");
em.getTransaction().commit();

System.out.println(em.find(Produto.class,1L));
ps: O código é apenas para demonstrar como isso é feito, não é funcional.

Agora para mudar esse exemplo para o modo otimista de ser basta criarmos uma propriedade no objeto com a anotação @Version para denotar que este campo será usado para o fim da implementação otimista. Esse campo deve ser int, long ou timestamp.

Com a adição do lock otimista quando o usuário B fosse tentar salvar suas modificações ele receberia a execeção OptimisticLockException. Isso já garantiria ao menos a notificação ao usuário que alguém estava trabalhando sobre o mesmo dado e ( lembra das canseiras que o IDE nos livra no versionamento de código) apartir dai você poderia mostrar o que foi mudado para o usuário tomar a decisão de salvar ou não suas alterações.

A parte chocante fica por conta do modo pessimista de ser, a JPA 1.0 não suporta diretamente o modo pessimista de ser (O JPA 2.0 prevê esse modo a mais :)

Então o que fazer?

Imaginem duas contas bancárias: (sempre esse exemplo) aMinhaConta (com saldo de R$ 150,00) e a suaConta (com saldo de R$ 25.000,00) e você quer me presentear com um Wii mas não tem como mandá-lo pelo correio, logo acha mais conviniente realizar uma transferência para que eu compre. O processo (bem simplificado) se resume a isso:

#0 quantiaASerDoada = R$ 1390,00;
#1 se suaConta.saldo > quantiaASerDoada então
#2 suaConta.transerePara(minhaConta, quantiaASerDoada);
#3 fim se

Se entre a linha 1 e 2 você fizer um saque de R$ 25.000,00 (isso pode ocorrer) a transferência não deveria ser realizada. Um modo para que isso ocorra é travar (lock) o dado que pode sofrer com essas concorrências. No JPA 1.0 você pode travar um objeto em dois passos (ai reside el peligro).

#0 Conta suaConta = em.find(Conta.class, 175789);
#1 em.lock(suaConta,LockMode.Write);

Mais uma vez entre a linha 0 e a 1 pode ocorrer um problema de concorrência. (tanto que a especificação JPA 2.0 já prêve um modo similar ao session do hibernate, o travamento no momento da leitura, em.find(Conta.class, 175789, LockMode.PESSIMISTIC);)

Solução fácil para o problema acima

Basta (se estiver usando Hibernate as your JPA provider) :

((Session) ((EntityManagerImpl) em.getDelegate()).getSession())

O session já tem um jeito de select for update session.get(SuaClasse.class, seuId, tipoDeTravamento). ( já perceberam que pra cada problema que você encontra na JPA 1.0 o hibernate quase sempre tem a solução?!)

Referências

http://en.wikibooks.org/wiki/Java_Persistence/Locking
http://www.javaworld.com/jw-07-2001/jw-0713-optimism.html

quinta-feira, 22 de outubro de 2009

Organizacao é tudo

Para as pessoas que moram no Rio de Janeiro ou que tenham disponibilidade para verem o evento Caelum Day | in Rio já bastaria dizer que o evento será no mínimo bom. Mas dessa notícia o que gostaria de destacar não é só o evento ( se puder ir, vá :) ) e sim a organização do site do evento... algo que deveria ser copiado, isso mesmo ctrl+c ctrl+v! Vejam o site do evento Caelum Day, ele possui as características padrões como : Programação do Evento , grandes nomes para palestrar (Philip Calçado), inscrições e etc. porém dentro dessas características comuns ele traz informações IMPORTANTÍSSIMAS como dicas de restaurantes, hotéis e até mesmo estacionamentos (dicas com valores :) ). Ahh1 o evento ocorrerá no dia 7 de Novembro de 2009 das 8h às 18h. Parabéns pela organização do evento.

Ahh2 : só pra complementar no final do evento será sorteado um Nintendo Wii. :)

sábado, 17 de outubro de 2009

Quer pagar quanto?

O portal de notícias da Record o R7 foi lançado a alguns dias atrás... até ai nada de anormal, certo?! Pois bem, fui verificar quanto valia o portal de acordo com o BizInformation. Se você ainda não conhece, se trata de um site que baseado em diversos parametros informa quanto seu site vale. Logo a primeira reação foi me assustar com o resultado para o site R7.com :

R$2.692,79

Somente isso! Imaginem meu site alternativo the empyrean foi cotado ao valor de :

$3,946.8

Outro detalhe é que para o site the empyrean foi usado (dolar americano) U$ ,ou seja, meu blog vale mais do que o portal R7 :-) brincadeira....
ps: penso que está claro o fato de que, o BizInformation, nesse caso do portal R7, falhou nas suas estátisticas.

quarta-feira, 7 de outubro de 2009

Livro DSL In Action

A friend of mine enviou-me um email informando sobre o livro DSL In Action (ainda não pronto) para uma possível pré-leitura. Há até mesmo um capítulo no site. Pelo capítulo grátis pra degustação, penso que o livro pode ser um grande amigão, gostei da forma com que o autor trata o assunto domain-specific language - dsl - e por isso fica a dica aqui de uma boa leitura. C0m certeza mais um livro a se somar na pilha de livros sobre dsl.