JPA 2: os novos recursos inspirados no Hibernate



Documentos relacionados
UFG - Instituto de Informática

JPA Passo a Passo. Henrique Eduardo M. Oliveira henrique@voffice.com.br. Globalcode Open4Education

Mapeamento Lógico/Relacional com JPA

Criar uma aplicação JPA2 com EclipseLink e H2

1 Criar uma entity a partir de uma web application que usa a Framework JavaServer Faces (JSF)

JPA: Persistência padronizada em Java

UFG - Instituto de Informática

Persistindo dados com TopLink no NetBeans

JPA Java Persistence API. Prof. Ramon Chiara

Orientação a Objetos

Persistência de dados com JPA. Hélder Antero Amaral Nunes

UFG - Instituto de Informática

Hibernate Envers Easy Entity Auditing

UFG - Instituto de Informática


Manipulação de Banco de Dados com Java. Ms. Bruno Crestani Calegaro Maio/ 2015

DOCUMENTAÇÃO DO FRAMEWORK - versão 2.0

UFG - Instituto de Informática

Java Persistence API. Entity Entity Campos e Propriedades Entity Chaves Primárias Entity Associações

HIBERNATE EM APLICAÇÃO JAVA WEB

Auditando persistência com JPA

Aula 5. Carlos Eduardo de Carvalho Dantas

Introdução a Java. Hélder Nunes

Prática da Disciplina de Sistemas Distribuídos Serviços Web IFMA DAI Professor Mauro Lopes C. Silva

Orientação a Objetos

Implementando uma Classe e Criando Objetos a partir dela

Acessando um Banco de Dados

Uma Abordagem sobre Mapeamento Objeto Relacional com Hibernate

Android e Bancos de Dados

Etc & Tal. Volume 2 - Número 1 - Abril 2009 SBC HORIZONTES 44

DEFINIÇÃO DE MÉTODOS

Padrão J2EE Data Access Object (DAO)

Hibernate. Mapeamento O/R Marcio Aguiar Ribeiro

JDBC. Siga as instruções para instalar o banco de dados H2 e criar a tabela Alunos.

Persistência de Classes em Tabelas de Banco de Dados

Classes de Entidades Persistentes JDB

ARRAYS. Um array é um OBJETO que referencia (aponta) mais de um objeto ou armazena mais de um dado primitivo.

Parte I. Demoiselle Mail

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS

Java Persistence Query Language JPQL

Java 2 Standard Edition Como criar classes e objetos

Auditoria Avançada de Persistência com Hibernate, JPA e Envers

O nome ANT é uma sigla para another neat tool (mais uma ferramenta organizada), segundo seu autor James Duncan Davidson.

Documentação Usando o Javadoc

Coleções. Conceitos e Utilização Básica. c Professores de ALPRO I 05/2012. Faculdade de Informática PUCRS

Aplicabilidade: visão geral

Fixture-Factory. Criando objetos para seus testes. Como criar objetos através de templates para serem utilizados como massa de dados em seus testes.

ALTO DESEMPENHO UTILIZANDO FRAMEWORK HIBERNATE E PADRÃO JAVA PERSISTENCE API

Persistência de Dados em Java com JPA e Toplink

Prof. Raul Sidnei Wazlawick UFSC-CTC-INE. Fonte: Análise e Projeto de Sistemas de Informação Orientados a Objetos, 2ª Edição, Elsevier, 2010.

SISTEMA TYR DIAGRAMAS DE CLASSE E SEQUÊNCIA Empresa: Academia Universitária

Módulo 5 JPATransaction Camadas Turma Turma TurmaBC TurmaBC TurmaBC TurmaBC

Introdução a Banco de Dados

CONVENÇÃO DE CÓDIGO JAVA

Repeater no GASweb. Regiões

Padrões de Projeto. Singleton

Como criar um EJB. Criando um projeto EJB com um cliente WEB no Eclipse

Síntese das discussões do fórum Livro-APF: Julho/2010

Persistência com JPA2 e Hibernate TREINAMENTOS

Introdução. Tutorial do Xdoclet. Resumo

Guia de Fatores de Qualidade de OO e Java

UML Aspectos de projetos em Diagramas de classes

Programação Estruturada e Orientada a Objetos. Fundamentos Orientação a Objetos

PROGRAMAÇÃO ESTRUTURADA. CC 2º Período

Linguagem de Programação JAVA. Técnico em Informática Professora Michelle Nery

Java e Banco de Dados: JDBC, Hibernate e JPA

PROJETO PEDAGÓGICO DE CURSOS

Laboratório de Banco de Dados Aula 1 Acesso a Banco de Dados. Prof. Josenildo Silva jcsilva@ifma.edu.br

Slide 1 Deitel/Deitel, 8e. Java Como programar Copyright 2010 Pearson Education

LOGGING DE EVENTOS COM LOG4J

Figura 1. A Classe Java

Desmistificando o Hibernate Envers em 10 passos

2 Orientação a objetos na prática

CURSO DE PROGRAMAÇÃO EM JAVA

Hibernate. Mapeamento Objeto-Relacional. Prof. Anselmo Cardoso Paiva Prof. Geraldo Braz Junior

Aula 2 - Revisão de JPA (Java Persistence API)

Aula 4. Carlos Eduardo de Carvalho Dantas


Resolvendo objeto-relacional impedance mismatch com hibernate

EXERCÍCIOS SOBRE ORIENTAÇÃO A OBJETOS

Programação de Computadores - I. Profª Beatriz Profº Israel

Java. Marcio de Carvalho Victorino

Organizando Classes em Pacotes. Profa. Thienne Johnson EACH/USP

Lista de Contas: Assinatura. Lista de Contas. Listas de Contas: Descrição. Listas de Contas: Descrição. Listas de Contas: Descrição

Arquitetura de Rede de Computadores

O Komunik é uma ferramenta de comunicação interna que permite a interação completa entre todos os setores de uma empresa.

Introdução à JPA-Java Persistence API

Entendendo como funciona o NAT

Reuso com Herança a e Composiçã

Especificação do 3º Trabalho

Aula 2 - Revisão de JPA (Java Persistence API)

Tutorial: Programando no Linux

Aula 1 Acesso a Banco de Dados

Programação de Computadores - I. Profª Beatriz Profº Israel

Prevayler. Perola. André Luís Sales de Moraes Juliana Keiko Yamaguchi Tatiana Yuka Takaki

NetBeans. Conhecendo um pouco da IDE

Gerenciamento de Contatos

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE ESCOLA AGRÍCOLA DE JUNDIAÍ EAJ - PRONATEC / REDE etec MÓDULO III DESENVOLVIMENTO PROFESSOR ADDSON COSTA

TOTVS BA Guia de Customização Linha Logix

Transcrição:

artigo JPA 2: os novos recursos inspirados no Hibernate A JPA 2.0 está apta a permitir todos os poderosos recursos que utilizamos do Hibernate? Paulo Silveira (paulo.silveira@caelum.com.br): é bacharel e mestre em Ciência da Computação pela USP, trabalha com Java há 10 anos, sendo 5 anos com consultoria, desenvolvimento e treinamento na Caelum. Raphael Lacerda (raphael.lacerda@caelum.com.br): é bacharel em Ciência da Computação pela Universidade Católica de Brasília, analista de sistemas do Banco do Brasil e instrutor da unidade Caelum Brasília. Possui as certificações SCJP 5.0 e SCWCD 5.0. A JPA 1.0 foi um grande passo: uma API baseada na experiência e sucesso do Hibernate para interfacear as diversas ferramentas ORM existentes no mercado. Mesmo com ela, muitos recursos específicos do Hibernate como Criteria, Second Level Cache, entre outros, não estavam disponíveis, fazendo com que frequentemente precisássemos acessar o framework diretamente. Como fica isso na JPA 2.0? O EJB3 ajudou a popularizar as ferramentas de mapeamento objeto-relacional (ORMs), que careciam de uma especificação dentro do Java EE. Uma tentativa mais abrangente, o Java Data Objects (JDO), ocorreu previamente sem alcançar muito sucesso. Um dos principais fatos que fez a Java Persistence API 1.0 (JPA) suceder foi, sem sombra de dúvidas, ter se baseado no que o mercado já estava adotando em larga escala: o Hibernate. Apesar de ser mais popular que a JDO, a JPA 1.0 não possui uma série de recursos um tanto populares entre os usuários do Hibernate. Podemos citar dois em especial: a forma orientada a objetos de pesquisa (Criterias) e o cache de entidades entre diferentes EntityManagers (2nd level cache). Será que a JPA 2.0 cobre bem esses aspectos, de tal forma que teremos uma real liberdade de escolha entre as implementações de JPA? As implementações da JPA 2.0 Para usarmos a JPA 2.0, precisamos de um persistence provider. Temos diversas opções, como o Hibernate, a OpenJPA e o EclipseLink. O Hibernate está em sua versão 3.5 beta2, sem a implementação de alguns recursos de Criteria aqui explorados. Usaremos o EclipseLink como exemplo que, além de ser a implementação de referência do Java EE 6, é um excelente teste para saber se os clássicos recursos presentes no Hibernate estão sendo bem implementados em outros providers.

Usando o EclipseLink e nosso modelo de classes Para utilizar a JPA 2.0 com o EclipseLink, basta você criar um projeto que contenha o eclipselink.jar, o jar da javax.persistence (que vem no pacote do EclipseLink) e o driver JDBC do seu banco de dados no build path do seu projeto. Além disso, você precisa configurar o persistence.xml dentro do META-INF (no eclipse, basta criar esse diretório dentro do seu src, que ele será criado no bin). A Listagem 1 mostra o persitence.xml configurado para o MySQL. Repare que muitas das propriedades foram padronizadas (não iniciam mais com hibernate ou eclipselink). Apenas as mais específicas dependem do provider que você está utilizando. As Listagens 2 e 3 mostram as classes Fornecedor e ContaPagar, que formam um relacionamento one-to-many bidirecional, mapeadas com as anotações já conhecidas da JPA 1.0, que serão utilizadas nos nossos testes. As Listagens 4 e 5 mostram uma simples classe JPAUtil apenas para facilitar nossos exemplos (no projeto, deve-se utilizar injeção de dependências para quem precisar de um EntityManager) além de uma superclasse para os testes dos nossos DAOs, que populam o banco de dados. Esse teste, somado a opção drop-and-create-tables do persistence.xml, faz com que uma pequena base seja populada para usarmos nas asserções. Esse superteste já utiliza do método save dos DAOs que veremos a seguir. Listagem 1. Persistence.xml. <persistence xmlns= http://java.sun.com/xml/ns/persistence xmlns:xsi= http://www.w3.org/2001/xmlschema-instance xsi:schemalocation= http://java.sun.com/xml/ns/persistence http:// java.sun.com/xml/ns/persistence/persistence_2_0.xsd version= 2.0 > <persistence-unit name= caelum > <class>br.com.caelum.fornecedor</class> <class>br.com.caelum.contapagar</class> <properties> <property name= javax.persistence.jdbc.driver value= com.mysql.jdbc.driver /> <property name= javax.persistence.jdbc.url value= jdbc:mysql://localhost/caelum /> <property name= javax.persistence.jdbc.user value= root /> <property name= javax.persistence.jdbc.password value= /> <property name= eclipselink.ddl-generation value= drop-and-create-tables /> <property name= eclipselink.ddl-generation.output-mode value= database /> <property name= eclipselink.logging.level value= FINE /> </properties> </persistence-unit> </persistence> Listagem 2. Atributos da entidade Fornecedor @Entity public class Fornecedor { @Id @GeneratedValue private int id; private String nome; @OneToMany(mappedBy= fornecedor ) private List<ContaPagar> contas; // além de construtores auxiliares e getters Listagem 3. Atributos da entidade ContaPagar. @Entity public class ContaPagar { @Id @GeneratedValue private int id; Criteria private String descricao; private Double valor; @ManyToOne private Fornecedor fornecedor; // além de construtores auxiliares e getters Listagem 4. Uma classe JPAUtil apenas para nossos testes. public class JPAUtil { private static EntityManagerFactory factory; public static EntityManager openmanager() { if (factory == null) factory = Persistence.createEntityManagerFactory( caelum ); return factory.createentitymanager(); public static void terminate() { factory.close(); factory = null; No Hibernate, é bem fácil criar um objeto que realizará uma pesquisa para retornar todos os fornecedores da nossa base de dados: session.createcriteria(fornecedor.class).list(); Como fica essa query com a JPA 2.0? A Listagem 6 mostra ela em uma forma minimal, que pode assustar no começo. Para dar um grande poder ao Criteria, a JPA 2.0 pode parecer um pouco verborrágica para quem estava acostumado com o modo sucinto do Hibernate. Se quisermos buscar por todos os valores de todas as contas a pagar do nosso sistema, no Hibernate podemos fazer uma Criteria como a seguinte: Projection property = Projections.property( valor ); session.createcriteria(contapagar.class).setprojection(property).list(); Já usando a JPA 2.0, utilizamos os selects em vez de projections. Para realizar a mesma pesquisa, devemos utilizar a Criteria do ContaPagarDAO mostrada na Listagem 7. 62 www.mundoj.com.br

Listagem 5. A superclasse dos nossos testes que popula a base. public class DaoTest { protected FornecedorDao fornecedordao; protected ContaPagarDao contadao; protected EntityManager manager; @Before public void setup() { this.manager = JPAUtil.openManager(); this.manager.gettransaction().begin(); this.fornecedordao = new FornecedorDao(manager); this.contadao = new ContaPagarDao(manager); // utilizando construtores auxiliares Fornecedor f1 = new Fornecedor( kalunga ); Fornecedor f2 = new Fornecedor( supervinhos ); Fornecedor f3 = new Fornecedor( saraiva ); ContaPagar cp1 = new ContaPagar( resmas, 100, f1); ContaPagar cp2 = new ContaPagar( canetas, 250, f1); ContaPagar cp3 = new ContaPagar( livros, 300, f3); this.fornecedordao.save(f1); this.fornecedordao.save(f2); this.fornecedordao.save(f3); this.contadao.save(cp1); this.contadao.save(cp2); this.contadao.save(cp3); this.manager.gettransaction().commit(); @After public void teardown() { this.manager.close(); JPAUtil.terminate(); Listagem 6. FornecedorDAO e método para listar todos os fornecedores. public class FornecedorDao { private final EntityManager manager; public FornecedorDao(EntityManager manager) { this.manager = manager; Listagem 7. ContaPagarDAO e método para listar todos valores das contas(projection). public class ContaPagarDao { private final EntityManager manager; public ContaPagarDao(EntityManager manager) { this.manager = manager; public void save(contapagar cp) { this.manager.persist(cp); public List<Double> listtodosvalores() { CriteriaQuery<Double> cq = cb.createquery(double.class); Root<ContaPagar> cpagar = cq.from(contapagar.class); CriteriaQuery<Double> select = cq.select(cpagar.<double>get( valor )); return this.manager.createquery(select).getresultlist(); Apesar do intuito do artigo não ser ensinar a API nova de Criteria, e sim comparar seu poder ao do Hibernate, começa a ficar claro a analogia. O método createquery recebe o tipo de objeto que será retornado no momento da execução; o método from define o ponto de partida da pesquisa. Com a CriteriaQuery em mãos, já é possível criar uma TypedQuery através do método createquery, como foi feito no primeiro exemplo da Listagem 6. Também temos objetos que representam Paths (e suas filhas Root e Join), como as referências fornecedor e cpagar da listagem. Essas referências podem ser utilizadas para os selects (no lugar das antigas projections do hibernate), dessa forma evitando um pouco as Strings em excesso, mas criando a necessidade de escrever mais código. O CriteriaBuilder possui um número muito grande de métodos para criar Expressions, que são objetos semelhantes aos Criterions do Hibernate. O CriteriaBuilder nada mais é que uma fábrica para muitas Expressions, assim como no Hibernate temos as classes Restrictions, Property e Order que fabricam Criterions. Como fica uma Criteria mais complicada? Imagine que precisamos listar quanto dinheiro foi gasto com cada fornecedor. Para isso, precisamos fazer uma Criteria que busca por todos fornecedores, fazendo join com as respectivas contas, agrupando pelo fornecedor e, desejando que no relatório conste também os que não possuem pagamentos, precisamos utilizar um left outer join. Com o Hibernate diretamente, teríamos algo como: public List<Fornecedor> listtodosfornecedores() { CriteriaQuery<Fornecedor> cq = cb.createquery(fornecedor.class); return this.manager.createquery(cq).getresultlist(); session.createcriteria(fornecedor.class, f ).createcriteria( contas, c, Criteria.LEFT_JOIN).setProjection( Projections.projectionList().add(Projections.property( f.nome )).add(projections.sum( c.valor )).add(projections.groupproperty( c.fornecedor )) ).addorder(order.asc( nome )).list(); 63

A Listagem 8 mostra uma Criteria da JPA 2.0 que obtém o mesmo resultado, e a Listagem 9 mostra seu teste, no qual obtemos como resultado 350 reais gastos na Kalunga, 300 na Saraiva, e null como resultado para o Supervinhos. Repare como a expressão cb.sum(cpagar.<double> get("valor") é interessante, pois fica claro que estamos somando os valores do objeto retornado pelo nosso join. Infelizmente, como não declaramos uma variável para o Path retornado por cpagar.get( valor ) o Java não consegue inferir Path<Double>, forçando a generificação da invocação, pois o método sum do CriteriaBuilder espera por Expressions que envolvam Number. Uma Tuple é uma forma um pouco mais interessante de trabalhar com resultados que retornam mais de um valor, porém você poderia utilizar Object[] como na Criteria do Hibernate, passando Object[].class para o createquery. O método multiselect recebe um varargs, onde passamos tudo que queremos receber de resposta nas nossas tuplas. Listagem 8. Método do FornecedorDAO para fazer o relatório de quanto gastamos com cada fornecedor. public List<Tuple> listacontasporfornecedor() { public class FornecedorDaoTest extends DaoTest { CriteriaQuery<Tuple> cq = cb.createtuplequery(); ListJoin<Object, Object> cpagar = fornecedor.joinlist( contas, JoinType.LEFT); cq.groupby(fornecedor); cq.orderby(cb.asc(fornecedor.get( nome ))); return this.manager.createquery( cq.multiselect(fornecedor, cb.sum(cpagar.<double> get( valor )))).getresultlist(); Listagem 9. Teste do método da Listagem 8. @Test public void testalistagemdascontasporfornecedor() { List<Tuple> lista = this.fornecedordao.listacontasporfornecedor(); Assert.assertEquals(3, lista.size()); Assert.assertEquals( kalunga, ((Fornecedor) lista.get(0).get(0)). getnome()); Assert.assertEquals(350d, ((Double) lista.get(0).get(1)). doublevalue(), 0.1); Assert.assertEquals( saraiva, ((Fornecedor) lista.get(1).get(0)). getnome()); Assert.assertEquals(300d, ((Double) lista.get(1).get(1)). doublevalue(), 0.1); Assert.assertEquals( supervinhos, ((Fornecedor) lista.get(2). get(0)).getnome()); Assert.assertNull(lista.get(2).get(1)); O metamodelo dinâmico A JPA 2.0 traz o conceito de metamodelo das entidades, algo análogo ao metamodelo (schema) do banco de dados, porém sem pensar no banco. Através do método getmetamodel podemos acessar todas as entidades e respectivos atributos e relacionamentos (Attributes e suas interfaces filhas). Esses atributos podem ser usados como argumentos para criar os Paths do Criteria, dando um pouco mais de segurança de tipos. A Listagem 10 utiliza esse recurso para executar a mesma query da Listagem 9. Repare que o join referenciado pela variável cpagar agora está tipado por Fornecedor e ContaPagar (anteriormente eram Objects). Mesmo com tanto código, ainda continuamos com algumas Strings, que ainda podem gerar erros em tempo de execução. Listagem 10. Mesma query da Listagem 8, agora com modelo dinâmico. public List<Tuple> listacontasporfornecedor() { Metamodel model = manager.getmetamodel(); CriteriaQuery<Tuple> cq = cb.createtuplequery(); EntityType<Fornecedor> fonecedorentity = model. entity(fornecedor.class); ListJoin<Fornecedor, ContaPagar> cpagar = fornecedor.join(fonecedorentity.getlist( contas, ContaPagar.class), JoinType.LEFT); cq.groupby(fornecedor); cq.orderby(cb.asc (fornecedor.get (fonecedorentity.getsingularattribute( nome )))); EntityType<ContaPagar> contapagarentity = model.entity(contapagar.class); CriteriaQuery<Tuple> x = cq.multiselect(fornecedor, cb.sum(cpagar.get (contapagarentity.getsingularattribute( valor, Double.class)))); return this.manager.createquery(x).getresultlist(); O metamodelo estático Como poderíamos criar uma Criteria sem nenhuma referência a Strings, reduzindo o risco de erros em tempo de execução de queries para praticamente zero? Precisaríamos nos referenciar a atributos da classe com verificação do compilador. Infelizmente o Java ainda não possui um recurso para referenciar aos objetos Method, Field e Constructor como sendo literais (isso é possível para objetos do tipo Class, através das expressões Classe.class). Pensando nessa carência, os líderes da JPA 2.0 chegaram a um consenso: utilizar classes auxiliares com atributos estáticos que representem os atributos das nossas entidades e possam ser passadas como parâmetros: o metamodelo estático, como os da Listagens 11 e 12. Esse metamodelo possui uma forma canônica muito bem definida, com 64 www.mundoj.com.br

padrões de nomenclatura e como cada atributo deve ser declarado. Isso é, o uso do underscore e das interfaces filhas de Attribute (SingularAttribute, ListAttribute etc.) são bem definidas em relação à sua utilização. Listagem 11. Metamodelo da classe Fornecedor. @StaticMetamodel(Fornecedor.class) public abstract class Fornecedor_ { public static volatile SingularAttribute<Fornecedor, Integer> id; public static volatile SingularAttribute<Fornecedor, String> nome; public static volatile ListAttribute<Fornecedor, ContaPagar> contas; Listagem 12. Metamodelo da classe ContaPagar. @StaticMetamodel(ContaPagar.class) public abstract class ContaPagar_ { public static volatile SingularAttribute<ContaPagar, Integer> id; public static volatile SingularAttribute<ContaPagar, String> descricao; public static volatile SingularAttribute<ContaPagar, Double> valor; public static volatile SingularAttribute<ContaPagar, Fornecedor> fornecedor; Com essas classes de metamodelo estático, podemos em vez de usar os métodos getattribute das entidades devolvidas pelo metamodelo dinâmico, passar esse valores referenciando diretamente pela estranha forma Entidade_.nomeDoAtributo. Fazemos isso na Listagem 13, que diminui bastante o código anteriormente feito com o modelo dinâmico, mantendo a tipagem forte. Listagem 13. Query da Listagem 8 utilizando os metamodelos estáticos. public List<Tuple> listacontasporfornecedor() { CriteriaQuery<Tuple> cq = cb.createtuplequery(); ListJoin<Fornecedor, ContaPagar> cpagar = fornecedor.join(fornecedor_.contas, JoinType.LEFT); cq.groupby(fornecedor); cq.orderby(cb.asc(fornecedor.get(fornecedor_.nome))); CriteriaQuery<Tuple> x = cq.multiselect (fornecedor, cb.sum(cpagar.get(contapagar_.valor))); return this.manager.createquery(x).getresultlist(); Porém daria bastante trabalho ter de escrever esses metamodelos estáticos e mantê-los atualizados (além de esses atributos ainda estarem null!). A JPA 2.0 define um modelo estático canônico, que deve ser gerado pelo provider, que por sua vez usa APT. O Annotation Processor Tool (APT) existe desde o Java 5 para gerar código baseado em algumas anotações, por um Processor. No Java 6 isso deve ser feito automaticamente pelo compilador: ele deve procurar por JARs no classpath que possuam dentro de META-INF/services o arquivo javax.annotation.processing.processor, definindo os Processors que devem ser invocados. No caso do Eclipse e do Hibernate, eles possuem JARs com esses arquivos, fazendo com que esse metamodelo seja gerado automaticamente a cada compilação. Para ativar o APT no Eclipse, você precisa ir nas propriedades do projeto e dentro de Java Compiler habilitar o Annotation Processing, e dentro do Factory Path colocar o jar de metamodelo (que no Hibernate e EclipseLink são jars separados). Caso prefira, pode usar uma task do ant semelhante à Listagem 14 apenas para fazer esse trabalho. Listagem 14. Build.xml para invocar os processadores, no nosso caso para gerar MetaModel. <project name= jpa2 default= generate-metamodel > <path id= lib > <fileset dir= lib > <include name= *.jar /> </fileset> </path> <target name= clean > <delete dir= generated /> <mkdir dir= generated /> </target> <target name= generate-metamodel depends= clean > <javac srcdir= src destdir= generated debug= true > <compilerarg value= -proc:only /> <classpath> <path refid= lib /> </classpath> </javac> </target> </project> Então temos três maneiras bem diferentes de criar a mesma Query: inteiramente baseada em Strings, uma com o metamodelo dinâmico, e outra com o metamodelo estático, além de poder combiná-las entre si. A proposta inicial era de não haver a opção de utilizar Criterias sem os metamodelos, que tornaria impossível a join query montada inicialmente neste artigo. Qual dessas formas é a mais indicada? Qual será que o mercado vai adotar? Certamente a tipagem forte é atraente, porém o metamodelo estático, além de trazer estranhamento para os desenvolvedores Java, assusta ainda mais quem está acostumado com as Criterias do Hibernate, muito mais sucintas. Second level cache O recurso de second cache level (cache de segundo nível) já é conhecido pelos desenvolvedores adeptos do Hibernate e agora está de certa forma especificado no JPA 2.0. Através dele evitamos que objetos sejam buscados do banco de dados mais de uma vez, já que internamente é guardado uma associação entre a chave primária e o objeto para cada entidade cacheada. O trade-off de se usar o segundo nível de cache também já é conhecido, inclusive as soluções para os problemas de "stale read" (leitura obsoleta o objeto que está em cache é uma versão mais antiga do que a que está no banco de dados no caso de base compartilhada entre aplicações). Caso se deseje contornar este problema, deve-se usar uma estratégia de cache 65

apropriada e configurar tempos de expiração. Trabalhar com segundo nível de cache é totalmente transparente para o desenvolvedor. Uma diferença importante é como os providers usufruem desse recurso. O EclipseLink já vem com cache de segundo nível habilitado por padrão e utiliza seu próprio cache. Já se você for trabalhar com Hibernate, deve informar quem será o provider de cache (como o EhCache ou JBoss Tree Cache), assim como parâmetros de customização (como o tamanho do pool no ehcache.xml). Na documentação da especificação (item 3.7) estão definidas algumas propriedades para se configurar o cache de segundo nível e, além disso, deixa a cargo do provider permitir a escolha de outros detalhes. No artigo, será mostrado como configurar o segundo nível de cache do EclipseLink usando JPA 2.0, que por opção, já vem habilitado. Logo, ao anotar uma entidade com @Entity, ela já é candidata a ser cacheada assim que você começar a manipulá-la com o EntityManager. Caso queira que alguma entidade e seu estado não sejam cacheados pelo EclipseLink, deve-se anotá-la com @Cacheable(false). Esta anotação especifica se uma entidade deve ser cacheada. Entretanto, seu comportamento pode ser alterado dependendo de como o elemento shared-cache-mode localizado no persistence.xml foi configurado (ver Listagem 15). Além da anotação @Cacheable, a especificação fornece meios para customizar o cache de acordo com a necessidade. O principal elemento é o shared-cache-mode, que define se as entidades e seus estados irão ser cacheados. Esse elemento é uma tag aninhada do persistence-unit (ver Listagem 16) que aceita os seguintes valores como parâmetros para definir quais estratégias o provider de cache vai adotar: nada entidade estiver anotada com @Cacheable(true), ela não será cacheada. O shared-cache-mode no persistence.xml tem preferência sobre as anotações nas entidades cache-mode no xml. Logo, a configuração padrão do provider será aplicada. Por fim, esses dois últimos parâmetros são usados em conjunto com a anotação @Cacheable. especificado. Entidades que não tiveram o elemento especificado ou foram anotadas com @Cacheable(false) não são cacheadas. ceção das que forem anotadas com @Cacheable(false). Retrieve and Store Busca e armazenamento de elementos na cache Pode-se definir propriedades para trabalhar com cache nas operações de busca e armazenamento de elementos no próprio EntityManager (método setproperty). As enums javax.persistence.cacheretrievemode e javax.persistence.cachestoremode fornecem estratégias (USE, BYPASS, REFRESH) para decisões de uso da cache para determinada ação. Como exemplo, o método find ou quando um dado é persistido. A exceção é o método refresh, que sempre vai fazer o BYPASS (acessar diretamente o banco de dados sem procurar em nenhuma cache). A tag shared-cache-mode tem preferência sobre esses elementos também, caso seja configurada como NONE, essas propriedades são ignoradas. O código da Listagem 17 mostra como verificar o uso do segundo nível de cache. Repare que o Eclipselink executa o select para buscar o fornecedor, já para o segundo Entity Manager (linha 6) ele busca o fornecedor que está cacheado. Agora a Listagem 18 mostra uma forma de desabilitar o segundo nível de cache e executar o mesmo código da Listagem 17, repare na saída do log que agora o eclipse link realiza dois selects na base. Listagem 15 Mapeamento de caches para entidades com @Cacheable. @Entity @Cacheable(false) //Significa que a entidade e seu estado não devem ser cachedados pelo provider. Class Fornecedor{ @Entity//Significa que a entidade e seu estado devem ser cachedados pelo provider. //ou @Cacheable(true) Class Fornecedor{ Listagem 16 Possíveis estratégias de cache com shared-cache-mode. <persistence-unit name= caelum > <shared-cache-mode>all</shared-cache-mode> <shared-cache-mode>none</shared-cache-mode> <shared-cache-mode>unspecified</shared-cache-mode> <shared-cache-mode>enable_selective</shared-cache-mode> <shared-cache-mode>disable_selective </shared-cache-mode> </persistence-unit> Listagem 17 Uso do segundo nível de cache. EntityManager em = JPAUtil.openManager(); Fornecedor f1 = em.find(fornecedor.class, 1); System.out.println( Primeiro Fornecedor: + f1.getnome()); EntityManager em2 = JPAUtil.openManager(); Fornecedor f2 = em2.find(fornecedor.class, 1); System.out.println( Segundo Fornecedor: + f2.getnome()); Log de saída no console (<property name="eclipselink.logging.thread" value="true" /> configurado no persistence.xml): [EL Fine]: Connection(5165021)--Thread(Thread[main,5,main])--SELECT ID, NOME FROM FORNECEDOR WHERE (ID =?) bind => [1] [EL Finest]: Thread(Thread[main,5,main])--Register the existing object kalunga Primeiro Fornecedor: kalunga [EL Finer]: Thread(Thread[main,5,main])--client acquired Segundo Fornecedor: kalunga [EL Finer]: Thread(Thread[main,5,main])--release unit of work 66 www.mundoj.com.br

Listagem 18. Desabilitar o segundo nível de cache. <shared-cache-mode>none</shared-cache-mode> [EL Fine]: Connection(2868213)--Thread(Thread[main,5,main])--SELECT ID, NOME FROM FORNECEDOR WHERE (ID =?)bind => [1] Primeiro Fornecedor: kalunga [EL Finer]: Thread(Thread[main,5,main])--client acquired [EL Fine]: Connection(2868213)--Thread(Thread[main,5,main])--SELECT ID, NOME FROM FORNECEDOR WHERE (ID =?)bind => [1] Segundo Fornecedor: kalunga [EL Finer]: Thread(Thread[main,5,main])--release unit of work Caso você queira testar os códigos aqui apresentados no Hibernate, basta colocar os jars do Hibernate 3.5 no seu path e retirar do EclipseLink, sem nem ter de especificar o persistence provider. Para a versão atual beta você ainda precisa definir as antigas propriedades do Hibernate como hibernate.connection.driver_class, entre outros. A versão com total suporte a JPA 2.0 deve sair muito em breve, e o grupo resolveu unir os três projetos (core, annotations e entitymanager) numa única distribuição, Considerações finais A JPA 2.0 não só implementa os recursos da Criteria criados e popularizados pelo Hibernate como vai além, dando a possibilidade do uso fortemente tipado, as custas de mais linhas de código. Já o second level cache, apesar de presente, continua contando com muitas configurações dependentes do seu persistence provider, que não ajuda muito em uma teórica mudança entre providers. Outros recursos muito importantes não foram padronizados, como configurações de connection pool e o gerenciamento de estatísticas (como o HibernateStatistics), mas a JPA 2.0 ainda traz diversos mapeamentos que antes só eram possíveis com as anotações específicas do Hibernate Annotations. Referências - 67