You are on page 1of 111

TREINAMENTOS

Persistncia com JPA2 e Hibernate

Persistncia com JPA 2 e Hibernate

14 de maro de 2011

www.k19.com.br

ii

Sumrio
1 Introduo 1.1 Persistncia . . . . . . 1.2 Congurao . . . . . 1.3 Mapeamento . . . . . 1.4 Gerando o banco . . . 1.5 Exerccios . . . . . . . 1.6 Manipulando entidades 1.6.1 Persistindo . . 1.6.2 Buscando . . . 1.6.3 Removendo . . 1.6.4 Atualizando . . 1.6.5 Listando . . . 1.6.6 Transaes . . 1.7 Exerccios . . . . . . . 1 1 1 2 3 3 5 5 5 6 6 6 6 7 9 9 10 10 10 11 11 12 12 13 14 15 16 17 19 20 21 22 27 28 28

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

Mapeamento 2.1 Entidades . . . . . . . . . . . 2.2 Denindo Restries . . . . . 2.3 @GeneratedValue . . . . . . . 2.4 Mapeamento Automtico . . . 2.5 Large Objects (LOB) . . . . . 2.6 Data e Hora . . . . . . . . . . 2.7 Dados Transientes . . . . . . . 2.8 Field Access e Property Access 2.9 Exerccios . . . . . . . . . . . 2.10 Relacionamentos . . . . . . . 2.10.1 One to One . . . . . . 2.10.2 One to Many . . . . . 2.10.3 Many to One . . . . . 2.10.4 Many to Many . . . . 2.11 Relacionamentos Bidirecionais 2.12 Objetos Embutidos . . . . . . 2.13 Exerccios . . . . . . . . . . . 2.14 Herana . . . . . . . . . . . . 2.14.1 Single Table . . . . . 2.14.2 Joined . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

iii

SUMRIO

SUMRIO

2.14.3 Table Per Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 2.15 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3 Entity Manager 3.1 Estados . . . . . . . . . . . . . . . . . . . . . 3.2 Sincronizao com o Banco de Dados . . . . . 3.2.1 Flush Mode . . . . . . . . . . . . . . . 3.3 Transies . . . . . . . . . . . . . . . . . . . . 3.3.1 New -> Managed . . . . . . . . . . . . 3.3.2 BD -> Managed . . . . . . . . . . . . 3.3.3 Managed -> Detached . . . . . . . . . 3.3.4 Detached -> Managed . . . . . . . . . 3.3.5 Managed -> Removed . . . . . . . . . 3.3.6 Managed -> Managed . . . . . . . . . 3.4 Regras de Transies . . . . . . . . . . . . . . 3.5 Exerccios . . . . . . . . . . . . . . . . . . . . 3.6 LAZY e EAGER . . . . . . . . . . . . . . . . 3.6.1 nd() VS getReference() . . . . . . . . 3.6.2 Fetch Type - Tipos Bsicos . . . . . . . 3.6.3 Fetch Type - Relacionamentos . . . . . 3.7 Lazy Initialization . . . . . . . . . . . . . . . . 3.8 Persistence Context ou Cache de Primeiro Nvel 3.9 Exerccios . . . . . . . . . . . . . . . . . . . . 3.10 Cascade . . . . . . . . . . . . . . . . . . . . . 3.11 Exerccios . . . . . . . . . . . . . . . . . . . . JPQL 4.1 Consultas Dinmicas . . . . . . 4.2 Named Query . . . . . . . . . . 4.3 Parmetros . . . . . . . . . . . 4.4 Exerccios . . . . . . . . . . . . 4.5 Tipos de Resultado . . . . . . . 4.5.1 Lista de Entidades . . . 4.5.2 Typed Query . . . . . . 4.5.3 Lista de Objetos Comuns 4.5.4 Valores nicos . . . . . 4.5.5 Resultados Especiais . . 4.5.6 Operador NEW . . . . . 4.6 Exerccios . . . . . . . . . . . . 4.7 Paginao . . . . . . . . . . . . 4.8 Exerccios . . . . . . . . . . . . 4.9 Operadores . . . . . . . . . . . 4.9.1 Condicionais . . . . . . 4.9.2 Escalares . . . . . . . . 4.9.3 Agregadores . . . . . . 4.9.4 Funes . . . . . . . . . 33 33 33 34 34 34 35 35 36 36 36 37 37 39 40 40 40 41 42 42 45 47 49 49 49 50 51 55 55 55 56 56 57 57 58 61 62 62 62 65 65 66 iv

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

www.k19.com.br

SUMRIO

SUMRIO

4.9.5 ORDER BY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4.10 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4.11 Referncias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 5 Criteria 5.1 Necessidade . . . . . . . . . . . 5.2 Estrutura Geral . . . . . . . . . 5.3 Exerccios . . . . . . . . . . . . 5.4 Tipos de Resultados . . . . . . . 5.4.1 Lista de Entidades . . . 5.4.2 Lista de Objetos Comuns 5.4.3 Valores nicos . . . . . 5.4.4 Resultados Especias . . 5.5 Exerccios . . . . . . . . . . . . 5.6 Filtros e Predicados . . . . . . . 5.7 Exerccios . . . . . . . . . . . . 5.8 Lista de Predicados . . . . . . . 5.9 Funes . . . . . . . . . . . . . 5.10 Ordenao . . . . . . . . . . . . 5.11 Subqueries . . . . . . . . . . . . 5.12 Exemplos . . . . . . . . . . . . 69 69 69 70 73 73 73 74 74 75 77 77 78 81 83 83 83 87 87 88 90 91 93 93 94 94 95 96 97 97 99 99 99 100 101 102 103

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

Tpicos Avanados 6.1 Operaes em Lote - Bulk Operations 6.2 Exerccios . . . . . . . . . . . . . . . 6.3 Concorrncia . . . . . . . . . . . . . 6.4 Exerccios . . . . . . . . . . . . . . . 6.5 Locking Otimista . . . . . . . . . . . 6.6 Exerccios . . . . . . . . . . . . . . . 6.7 Locking Pessimista . . . . . . . . . . 6.8 Exerccios . . . . . . . . . . . . . . . 6.9 Callbacks . . . . . . . . . . . . . . . 6.10 Exerccios . . . . . . . . . . . . . . . 6.11 Consultas Nativas . . . . . . . . . . . 6.12 Exerccios . . . . . . . . . . . . . . . Arquitetura 7.1 Inicializao do JPA . . . . . . 7.1.1 Aplicaes Java SE . . 7.1.2 Aplicaes Java EE . . 7.2 Repositrios . . . . . . . . . . 7.3 Controle de Transaes . . . . 7.3.1 Open Session in View

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

K19 Treinamentos

SUMRIO

SUMRIO

www.k19.com.br

vi

Captulo 1 Introduo
1.1 Persistncia

Aplicaes corporativas manipulam dados em grande quantidade. Na maioria dos casos, esses dados so armazenados em banco de dados relacionais pois os principais sistema gerenciadores de banco de dados do mercado utilizam o modelo relacional. Por outro lado, hoje em dia, as aplicaes corporativas costumam ser desenvolvidas com linguagens orientadas a objetos. Como o modelo relacional e o modelo orientado a objetos diferem no modo de estruturar os dados, uma transformao deve ocorrer toda vez que alguma informao trafegar da aplicao para o banco de dados ou vice-versa. Essa transformao no simples pois os dois modelos so bem diferentes. No contexto das aplicaes Java, para facilitar o processo de transformao dos dados que trafegam entre as aplicaes e os banco de dados, podemos utilizar algumas ferramentas de persistncia como o Hibernate ou o TopLink. Essas ferramentas funcionam como intermedirios entre as aplicaes e os banco de dados, automatizando diversos processos importantes relacionados persistncia dos dados. Elas so chamadas de ferramentas ORM (Object Relational Mapping) Com o intuito de facilitar a utilizao dessas ferramentas e torn-las compatveis com os outros recursos da plataforma Java, elas so padronizadas pela especicao Java Persistence API (JPA). Veremos nesse captulo, os passos principais para utilizar uma implementao da JPA. No caso, utilizaremos o Hibernate e o banco de dados MySQL.

1.2

Congurao

Antes de comear a utilizar o Hibernate, necessrio baixar do site ocial o bundle que inclui os jars do hibernate e todas as suas dependncias. Neste curso, utilizaremos a verso 3.5.1. A url do site ocial do Hibernate http://www.hibernate.org/. Veja tambm um artigo da K19 sobre congurao do Hibernate no seguinte endereo http://www.k19.com.br/artigos/configurando-hibernate-com-mysql/. Para congurar o Hibernate em uma aplicao, devemos criar um arquivo chamado persistence.xml. O contedo desse arquivo contm informaes sobre o banco de dados, como a url 1

Introduo de conexo, usurio e senha. Alm de dados sobre a implementao de JPA que ser utilizada. O arquivo PERSISTENCE . XML deve ser salvo em uma pasta chamada META-INF, que deve estar no classpath da aplicao. Veja abaixo um exemplo de congurao para o PERSIS TENCE . XML :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K19" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver "/> <property name="javax.persistence.jdbc.user" value="usuario"/> <property name="javax.persistence.jdbc.password" value="senha"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/k19"/> </properties> </persistence-unit> </persistence>

1.3

Mapeamento

Um dos principais objetivos dos frameworks ORM estabelecer o mapeamento entre os conceitos do modelo orientado a objetos e os conceitos do modelo entidade relacionamento. Este mapeamento pode ser denido atravs de xml ou de maneira mais prtica com anotaes Java. Quando utilizamos anotaes, evitamos a criao de extensos arquivos em xml. A seguir veremos as principais anotaes Java de mapeamento do JPA. Essas anotaes esto no pacote javax.persistence. @Entity a principal anotao do JPA. Ela que deve aparecer antes do nome de uma classe. E deve ser denida em todas as classes que tero objetos persistidos no banco de dados. As classes anotadas com @E NTITY so mapeadas para tabelas. Por conveno, as tabelas possuem os mesmos nomes das classes. Mas, podemos alterar esse comportamento utilizando a anotao @TABLE. Os atributos declarados em uma classe anotada com @E NTITY so mapeados para colunas na tabela correspondente classe. Outra vez, por conveno, as colunas possuem os mesmos nomes dos atributos. E novamente, podemos alterar esse padro utilizando para isso a anotao @C OLUMN. @Id Utilizada para indicar qual atributo de uma classe anotada com @E NTITY ser mapeado para a chave primria da tabela correspondente classe. Geralmente o atributo anotado com @I D do tipo L ONG. www.k19.com.br 2

Introduo @GeneratedValue Geralmente vem acompanhado da anotao @I D. Serve para indicar que o valor de um atributo que compe uma chave primria deve ser gerado pelo banco no momento em que um novo registro inserido.

1.4

Gerando o banco

Uma das vantagens de utilizar o Hibernate, que ele capaz de gerar as tabelas no banco de dados. Ele faz isso de acordo com as anotaes colocadas nas classes e as informaes presentes no PERSISTENCE . XML. As tabelas so geradas atravs de mtodo da classe P ERSISTENCE, o CREATE E NTITYM ANAGER FACTORY ( STRING PERSISTENCE U NIT ). O parmetro PERSISTENCE U NIT permite escolher, pelo nome, uma unidade de persistncia denida no PERSISTENCE . XML.
1 Persistence.createEntityManagerFactory("K19");

1.5

Exerccios

1. Crie um projeto no eclipse chamado JPA2-Hibernate. 2. Crie uma pasta chamada lib dentro do projeto JPA2-Hibernate. 3. Entre na pasta K19-Arquivos/Hibernate da rea de Trabalho e copie os jars do Hibernate para a pasta lib do projeto JPA2-Hibernate. 4. Entre na pasta K19-Arquivos/MySQL-Connector-JDBC da rea de Trabalho e copie o arquivo MYSQL - CONNECTOR - JAVA -5.1.13. BIN . JAR para pasta lib do projeto JPA2Hibernate. 5. Entre na pasta K19-Arquivos/SLF4J da rea de Trabalho e copie os jars para pasta lib do projeto JPA2-Hibernate. 6. Entre na pasta K19-Arquivos/Log4J da rea de Trabalho e copie o arquivo 1.2.16. JAR para pasta lib do projeto JPA2-Hibernate.
LOG 4 J -

7. Adicione os jars da pasta lib ao build path do projeto JPA2-Hibernate. Pea orientao do instrutor se for necessrio. 8. Crie uma pasta chamada META-INF dentro da pasta src do projeto JPA2-Hibernate. 9. Crie o arquivo de conguraes persistence.xml na pasta META-INF. Para no ter que digitar todo o cdigo copie o modelo persistence.xml da pasta K19-Arquivos/modelos da sua rea de Trabalho. 3 K19 Treinamentos

Introduo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_livraria" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver "/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="root"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_livraria"/> </properties> </persistence-unit> </persistence>

10. Crie uma classe para modelar as editoras da nossa livraria e acrescente as anotaes necessrias para fazer o mapeamento. Obs: As anotaes devem ser importadas do pacote JAVAX . PERSISTENCE .
1 2 3 4 5 6 7 8 9 10 11 @Entity public class Editora { @Id @GeneratedValue private Long id; private String nome; private String email; // GETTERS AND SETTERS }

11. Apague a base dados K21_livraria se ela existir atravs do MySQL Query Browser. Pea orientao do instrutor se for necessrio. 12. Crie a base dados K21_livraria atravs do MySQL Query Browser. Pea orientao do instrutor se for necessrio. 13. Congure o Log4J criando um arquivo chamado log4j.properties na pasta src do projeto JPA2-Hibernate.
log4j.rootCategory=INFO, CONSOLE log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%r [%t] %-5p %c - %m%n

14. Gere as tabelas atravs da classe P ERSISTENCE. Para isso, crie uma classe com mtodo MAIN . Obs: As classes devem ser importadas do pacote JAVAX . PERSISTENCE . www.k19.com.br 4

Introduo
1 2 3 4 5 6 7 8 public class GeraTabelas { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("livraria"); factory.close() } }

Atravs do MySQL Query Browser verique se a tabela E DITORA foi criada corretamente.

1.6

Manipulando entidades

Para manipular as entidades da nossa aplicao, devemos utilizar um E NTITY M ANAGER que obtido atravs de uma E NTITY M ANAGER FACTORY.
1 2 3 4 EntityManagerFactory factory = Persistence.createEntityManagerFactory("K19"); EntityManager manager = factory.createEntityManager();

1.6.1

Persistindo

Para armazenar as informaes de um objeto no banco de dados basta utilizar o mtodo PERSIST () do E NTITY M ANAGER .
1 2 3 4 5 Editora novaEditora = new Editora(); novaEditora.setNome("K19 - Livros") novaEditora.setEmail("contato@k19.com.br"); manager.persist(novaEditora);

1.6.2
FIND ()
1 2

Buscando

Para obter um objeto que contenha informaes do banco de dados basta utilizar o mtodo ou o GET R EFERENCE () do E NTITY M ANAGER.

Editora editora1 = manager.find(Editora.class, 1L); Editora editora2 = manager.getReference(Editora.class, 2L);

A diferena entre os dois mtodos bsicos de busca FIND () e GET R EFERENCE () que o primeiro recupera os dados desejados imediatamente j o segundo posterga at a primeira chamada de um mtodo GET do objeto. 5 K19 Treinamentos

Introduo

1.6.3

Removendo
REMOVE ()

Para remover um registro correspondente a um objeto basta utilizar o mtodo do E NTITY M ANAGER.
1 2 Editora editora1 = manager.find(Editora.class, 1L); manager.remove(editora1);

1.6.4

Atualizando

Para alterar os dados de um registro correspondente a um objeto basta utilizar os prprios mtodos setters desse objeto.
1 2 Editora editora1 = manager.find(Editora.class, 1L); editora.setNome("K19 - Livros e Publicaes");

1.6.5

Listando

Para obter uma listagem com todos os objetos referentes aos registros de uma tabela, devemos utilizar a linguagem de consulta do JPA, a JPQL que muito parecida com a linguagem SQL. A vantagem do JPQL em relao ao SQL que a sintaxe a mesma para bancos de dados diferentes.
1 2 Query query = manager.createQuery("SELECT e FROM Editora e"); List<Editora> editoras = query.getResultList();

1.6.6

Transaes

As modicaes realizadas nos objetos administrados por um E NTITY M ANAGER so mantidas em memria. Em certos momentos, necessrio sincronizar os dados da memria com os dados do banco de dados. Essa sincronizao deve ser realizada atravs de uma transao JPA criada pelo E NTITY M ANAGER que administra os objetos que desejamos sincronizar. Para abrir uma transao utilizamos o mtodo BEGIN ().
1 manager.getTransaction().begin();

FLUSH ()
1 2 3 4 5

Com a transao aberta podemos sincronizar os dados com o banco atravs do mtodo ou COMMIT ().

Editora editora1 = manager.find(Editora.class, 1L); editora.setNome("K19 - Livros e Publicaes"); manager.getTransaction().begin(); manager.flush();

www.k19.com.br

Introduo
1 2 3 4 5 Editora editora1 = manager.find(Editora.class, 1L); editora.setNome("K19 - Livros e Publicaes"); manager.getTransaction().begin(); manager.getTransaction().commit();

1.7

Exerccios

15. Crie um teste para inserir editoras no banco de dados.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class InsereEditoraComJPA { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("livraria"); EntityManager manager = factory.createEntityManager(); Editora novaEditora = new Editora(); Scanner entrada = new Scanner(System.in); System.out.println("Digite o nome da editora: "); novaEditora.setNome(entrada.nextLine()); System.out.println("Digite o email da editora: "); novaEditora.setEmail(entrada.nextLine()); manager.persist(novaEditora); manager.getTransaction().begin(); manager.getTransaction().commit(); factory.close(); } }

16. Crie um teste para listar as editoras inseridas no banco de dados.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ListaEditorasComJPA { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("livraria"); EntityManager manager = factory.createEntityManager(); Query query = manager.createQuery("SELECT e FROM Editora e"); List<Editora> editoras = query.getResultList(); for(Editora e : editoras) { System.out.println("EDITORA: " + e.getNome() + " - " + e.getEmail()); } } }

K19 Treinamentos

Introduo

www.k19.com.br

Captulo 2 Mapeamento
O mapeamento objeto relacional o corao do Hibernate e das outras implementaes de JPA pois ele dene quais transformaes devem ser realizadas nos dados para que essas informaes possam navegar da aplicao para o banco de dados ou do banco de dados para a aplicao. Alm disso, o mapeamento determina como a ferramenta ORM far consultas complexas envolvendo mais do que uma tabela.

2.1

Entidades

As classes da nossa aplicao que devem ser mapeadas para tabelas do banco de dados so anotadas com @Entity. Cada instncia de uma classe anotada com @E NTITY deve possuir um identicador nico. Em geral, esse identicador um atributo numrico que deve ser anotado com @Id.
1 2 3 4 5 @Entity class Pessoa { @Id private Long id; }

Por conveno, a classe P ESSOA ser mapeada para uma tabela com o mesmo nome (Pessoa). O atributo ID ser mapeado para uma coluna com o mesmo nome (id) na tabela Pessoa. Podemos no seguir o comportamento padro e aplicar nomes diferentes para as tabelas e colunas utilizando as anotaes @Table e @Column. A coluna correspondente ao atributo ID ser a chave primria da tabela P ESSOA por causa da anotao @I D.
1 2 3 4 5 6 7 @Entity @Table(name = "tbl_pessoas") class Pessoa { @Id @Column(name = "col_id") private Long id; }

Mapeamento

2.2

Denindo Restries

Podemos denir algumas restries para os atributos das nossas entidades atravs das propriedades da anotao @C OLUMN. Veja as principais propriedades abaixo: length nullable unique Limita a quantidade de caracteres de um valor string Determina se o campo pode possuir valores NULL ou no Determina se uma coluna pode ter valores repetidos ou no

1 2 3 4 5 6 7 8

@Entity class Pessoa { @Id private Long id; @Column(length=30,nullable=false,unique=true) private String nome; }

2.3

@GeneratedValue

Em geral, os bancos de dados oferecem algum mecanismo para gerar os valores de uma chave primria simples e numrica. Do ponto de vista do desenvolvedor JPA, para deixar com o banco de dados a responsabilidade de gerar os valores de uma chave primria simples e numrica, basta aplicar a anotao @GeneratedValue.
1 2 3 4 5 6 @Entity class Pessoa { @Id @GeneratedValue private Long id; }

2.4

Mapeamento Automtico

Alguns tipos do Java so mapeados automaticamente para tipos correspondentes do banco de dados tirando dos desenvolvedores esse trabalho. Eis uma listagem dos tipos que so mapeados automaticamente: Tipos primitivos (byte, short, char, int, long, oat, double e boolean) Classes Wrappers (Byte, Short, Character, Integer, Long, Float, Double e Boolean) String BigInteger e BigDecimal java.util.Date e java.util.Calendar www.k19.com.br 10

Mapeamento java.sql.Date, java.sql.Time e java.sql.Timestamp Array de byte ou char Enums Serializables

2.5

Large Objects (LOB)

Eventualmente, dados maiores do que o comum devem ser armazenados no banco de dados. Por exemplo, uma imagem, uma msica ou um texto com muitas palavras. Para esses casos, os bancos de dados oferecem tipos de dados especcos. Do ponto de vista do desenvolvedor JPA, basta aplicar a anotao @LOB em atributos do tipo S TRING, BYTE [], B YTE [], CHAR [] ou C HARACTER [] que o provedor (Hibernate, TopLink ou outra implementao de JPA) utilizar os procedimentos adequados para manipular esses dados.
1 2 3 4 5 6 7 8 9 @Entity class Pessoa { @Id @GeneratedValue private Long id; @Lob private byte[] avatar; }

2.6

Data e Hora

Comumente, as aplicaes Java utilizam as classes JAVA . UTIL .DATE e JAVA . UTIL .C ALENDAR para trabalhar com datas e horas. Essas classes so mapeadas automaticamente para tipos adequados no banco de dados. Portanto, basta declarar os atributos utilizando um desses dois tipos nas classes que sero mapeadas para tabelas.
1 2 3 4 5 6 7 8 @Entity class Pessoa { @Id @GeneratedValue private Long id; private Calendar nascimento; }

Por padro, quando aplicamos o tipo JAVA . UTIL .DATE ou JAVA . UTIL .C ALENDAR, tanto data quanto hora sero armazenados no banco de dados. Para mudar esse comportamento, devemos aplicar a anotao @Temporal escolhendo uma das trs opes abaixo: TemporalType.DATE : Apenas data (dia, ms e ano). TemporalType.TIME : Apenas horrio (hora, minuto e segundo) 11 K19 Treinamentos

Mapeamento TemporalType.TIMESTAMP (Padro): Data e Horrio

1 2 3 4 5 6 7 8 9

@Entity class Pessoa { @Id @GeneratedValue private Long id; @Temporal(TemporalType.DATE) private Calendar nascimento; }

2.7

Dados Transientes

Eventualmente, no desejamos que alguns atributos de um determinado grupo de objetos sejam persistidos no banco de dados. Nesse caso, devemos aplicar o modicador transient ou a anotao @Transient.
1 2 3 4 5 6 7 8 9 10 11 12 @Entity class Pessoa { @Id @GeneratedValue private Long id; @Temporal(TemporalType.DATE) private Calendar nascimento; @Transient private int idade; }

2.8

Field Access e Property Access

Os provedores de JPA precisam ter acesso ao estado das entidades para poder administrlas. Por exemplo, quando persistimos uma instncia de uma entidade, o provedor deve pegar os dados desse objeto e armazen-los no banco. Quando buscamos uma instncia de uma entidade, o provedor recupera as informaes correspondentes do banco de dados e guarda em um objeto. O JPA 2 dene dois modos de acesso ao estado das instncias das entidades: Field Access e Property Access. Quando colocamos as anotaes de mapeamento nos atributos, estamos optando pelo modo Field Access. Quando colocamos as anotaes de mapeamento nos mtodos getters, estamos optando pelo modo Property Accesss. No modo Field Access, os atributos dos objetos so acessados diretamente atravs de reection e no necessrio implementar mtodos getters e setters. No modo Property Access, os mtodos getters e setters devem ser implementados pelo desenvolvedor e sero utilizados pelo provedor para que ele possa acessar e modicar o estado dos objetos. www.k19.com.br 12

Mapeamento

2.9

Exerccios

1. Crie um projeto no eclipse chamado Mapeamento. Copie a pasta lib do projeto JPA2Hibernate para o projeto Mapeamento. Depois selecione todos os jars e os adicione no classpath. 2. Abra o MySQL Query Browser e apague a base de dados K21_mapeamento se existir. Depois crie a base de dados K21_mapeamento. 3. Copie a pasta META-INF do projeto JPA2-Hibernate para dentro da pasta src do projeto Mapeamento. Altere o arquivo persistence.xml do projeto Mapeamento, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_mapeamento" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver "/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="root"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_mapeamento"/> </properties> </persistence-unit> </persistence>

4. Crie uma entidade para modelar os usurios de uma rede social dentro de um pacote chamado modelo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Entity public class Usuario { @Id @GeneratedValue private Long id; @Column(unique=true) private String email; @Temporal(TemporalType.DATE) private Calendar dataDeCadastro; @Lob private byte[] foto; // GETTERS AND SETTERS }

13

K19 Treinamentos

Mapeamento 5. Adicione um usurio no banco de dados atravs do seguinte teste.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class AdicionaUsuario { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Usuario usuario = new Usuario(); usuario.setEmail("contato@k19.com.br"); usuario.setDataDeCadastro(Calendar.getInstance()); manager.persist(usuario); manager.getTransaction().commit(); manager.close(); factory.close(); } }

6. Abra o MySQL Query Browser e observe as propriedades da tabela Usuario da base de dados K21_mapeamento.

2.10

Relacionamentos

Os relacionamentos entre as entidades de um domnio devem ser expressos na modelagem atravs de vnculos entre classes. Podemos denir quatro tipos de relacionamentos de acordo com a cardinalidade. One to One (Um para Um) : Por exemplo, um estado governado por apenas um governador e um governador governa apenas um estado.

One to Many (Um para Muitos) : Por exemplo, um departamento possui muitos funcionrios e um funcionrio trabalha em apenas em um departamento.

Many to One (Muitos para Um) : Por exemplo, um pedido pertence a apenas um cliente e um cliente faz muitos pedidos. www.k19.com.br 14

Mapeamento

Many to Many (Muitos para Muitos) : Por exemplo, um livro possui muitos autores e um autor possui muitos livros.

2.10.1

One to One

Suponha que no nosso domnio h duas entidades: Estado e Governador. Devemos criar uma classe para cada entidade e aplicar nelas as anotaes bsicas de mapeamento.
1 2 3 4 5 6 @Entity class Estado { @Id @GeneratedValue private Long id; }

1 2 3 4 5 6

@Entity class Governador { @Id @GeneratedValue private Long id; }

Como existe um relacionamento entre estados e governadores devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe E STADO.
1 2 3 4 5 6 7 8 @Entity class Estado { @Id @GeneratedValue private Long id; private Governador governador; }

Alm disso, devemos informar ao provedor do JPA que o relacionamento que existe entre um estado e um governador do tipo One to One. Fazemos isso, aplicando a anotao @OneToOne no atributo que expressa o relacionamento. 15 K19 Treinamentos

Mapeamento
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id; @OneToOne private Governador governador; }

No banco de dados, a tabela referente a classe E STADO possura uma coluna de relacionamento tambm chamada de join column. Em geral, essa coluna ser denida como uma chave estrangeira associada tabela referente classe G OVERNADOR. Por padro, o nome da coluna de relacionamento a concatenao com _ da entidade alvo do relacionamento com o nome da chave primria tambm da entidade alvo. No exemplo de estados e governadores, a join column teria o nome governador_id. Podemos alterar o nome padro das join columns aplicando a anotao @JoinColumn.
1 2 3 4 5 6 7 8 9 10 @Entity class Estado { @Id @GeneratedValue private Long id; @OneToOne @JoinColumn(name="gov_id") private Governador governador; }

2.10.2

One to Many

Suponha que no nosso domnio h duas entidades: Departamento e Funcionrio. Criaramos duas classes com as anotaes bsicas de mapeamento.
1 2 3 4 5 6 @Entity class Departamento { @Id @GeneratedValue private Long id; }

1 2 3 4 5 6

@Entity class Funcionario { @Id @GeneratedValue private Long id; }

Como existe um relacionamento entre departamentos e funcionrios devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe D EPARTAMENTO. Supondo que um departamento pode possuir muitos funcionrios, devemos utilizar uma coleo para expressar esse relacionamento. www.k19.com.br 16

Mapeamento
1 2 3 4 5 6 7 8 @Entity class Departamento { @Id @GeneratedValue private Long id; private Collection<Funcionario> funcionarios; }

Para informar a cardinalidade do relacionamento entre departamentos e funcionrios, devemos utilizar a anotao @OneToMany na coleo.
1 2 3 4 5 6 7 8 9 @Entity class Departamento { @Id @GeneratedValue private Long id; @OneToMany private Collection<Funcionario> funcionarios; }

No banco de dados, alm das duas tabelas correspondentes s classes D EPARTAMENTO e F UNCIONARIO, uma terceira tabela ser criada para relacionar os registros dos departamentos com os registros dos funcionrios. Essa terceira tabela chamada de tabela de relacionamento ou join table. Por padro, o nome da join table a concatenao com _ dos nomes das duas entidades. No exemplo de departamentos e funcionrios, o nome do join table seria Departamento_Funcionario. Essa tabela possura duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table D EPARTAMENTO _F UNCIONARIO possura uma coluna chamada Departamento_id e outra chamada funcionarios_id. Para personalizar os nomes das colunas da join table e d prpria join table, podemos aplicar a anotao @JoinTable no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 10 11 12 @Entity class Departamento { @Id @GeneratedValue private Long id; @OneToMany @JoinTable(name="DEP_FUNC", joinColumns=@JoinColumn(name="DEP_ID"), inverseJoinColumns=@JoinColumn(name="FUNC_ID")) private Collection<Funcionario> funcionarios; }

2.10.3

Many to One

Suponha que no nosso domnio h duas entidades: Pedido e Cliente. As duas classes que modelariam essas entidades seriam anotadas com as anotaes principais de mapeamento. 17 K19 Treinamentos

Mapeamento
1 2 3 4 5 6 @Entity class Pedido { @Id @GeneratedValue private Long id; }

1 2 3 4 5 6

@Entity class Cliente { @Id @GeneratedValue private Long id; }

Como existe um relacionamento entre pedidos e clientes devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe P EDIDO. Supondo que um pedido pertence a um nico cliente, devemos utilizar um atributo simples para expressar esse relacionamento.

1 2 3 4 5 6 7 8

@Entity class Pedido { @Id @GeneratedValue private Long id; private Cliente cliente; }

Para informar a cardinalidade do relacionamento entre pedidos e clientes, devemos utilizar a anotao @ManyToOne no atributo.

1 2 3 4 5 6 7 8 9

@Entity class Pedido { @Id @GeneratedValue private Long id; @ManyToOne private Cliente cliente; }

No banco de dados, a tabela referente a classe P EDIDO possura uma join column vinculada tabela da classe C LIENTE. Por padro, o nome da join column a concatenao com _ da entidade alvo do relacionamento com o nome da chave primria tambm da entidade alvo. No exemplo de pedidos e clientes, o nome da join column seria cliente_id. Podemos alterar o nome padro das join columns aplicando a anotao @JoinColumn. www.k19.com.br 18

Mapeamento
1 2 3 4 5 6 7 8 9 10 @Entity class Pedido { @Id @GeneratedValue private Long id; @ManyToOne @JoinColumn(name="cli_id") private Cliente cliente; }

2.10.4

Many to Many

Suponha que no nosso domnio h duas entidades: livros e autores. As classes e com as anotaes bsicas de mapeamento seriam mais ou menos assim:
1 2 3 4 5 6 @Entity class Livro { @Id @GeneratedValue private Long id; }

1 2 3 4 5 6

@Entity class Autor { @Id @GeneratedValue private Long id; }

Como existe um relacionamento entre livros e autores devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe L IVRO. Supondo que um livro pode ser escrito por muitos autores, devemos utilizar uma coleo para expressar esse relacionamento.
1 2 3 4 5 6 7 8 @Entity class Livro { @Id @GeneratedValue private Long id; private Collection<Autor> autores; }

Para informar a cardinalidade do relacionamento entre livros e autores, devemos utilizar a anotao @ManyToMany na coleo. 19 K19 Treinamentos

Mapeamento
1 2 3 4 5 6 7 8 9 @Entity class Livro { @Id @GeneratedValue private Long id; @ManyToMany private Collection<Autor> autores; }

No banco de dados, alm das duas tabelas correspondentes s classes L IVRO e AUTOR, uma join table criada para relacionar os registros dos livros com os registros dos autores. Por padro, o nome da join table a concatenao com _ dos nomes das duas entidades. No exemplo de livros e autores, o nome do join table seria Livro_Autor. Essa tabela possura duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table L IVRO _AUTOR possura uma coluna chamada Livro_id e outra chamada autores_id. Para personalizar os nomes das colunas da join table e d prpria join table, podemos aplicar a anotao @JoinTable no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 10 11 12 @Entity class Livro { @Id @GeneratedValue private Long id; @ManyToMany @JoinTable(name="Liv_Aut", joinColumns=@JoinColumn(name="Liv_ID"), inverseJoinColumns=@JoinColumn(name="Aut_ID")) private Collection<Autor> autores; }

2.11

Relacionamentos Bidirecionais

Quando expressamos um relacionamento entre entidades colocando um atributo em uma das entidades, podemos acessar a outra entidade a partir da primeira. Por exemplo, suponha o relacionamento entre governadores e estados.
1 2 3 4 5 6 7 8 9 10 11 @Entity class Estado { @Id @GeneratedValue private Long id; @OneToOne private Governador governador; // GETTERS E SETTERS }

Como o relacionamento est denido na classe E STADO podemos acessar o governador a partir de um estado. www.k19.com.br 20

Mapeamento
1 2 Estado e = manager.find(Estado.class, 1L); Governador g = e.getGovernador();

Podemos expressar o relacionamento na classe G OVERNADOR tambm. Dessa forma, poderamos acessar um estado a partir de um governador.
1 2 3 4 5 6 7 8 9 10 11 @Entity class Governador { @Id @GeneratedValue private Long id; @OneToOne private Estado estado; // GETTERS E SETTERS }

1 2

Governador g = manager.find(Governador.class, 1L); Estado e = g.getEstado();

Porm, devemos indicar em uma das classes que esse relacionamento bidirecional a juno de dois relacionamentos unidirecionais. Caso contrrio, o provedor do JPA ir considerar dois relacionamentos distintos mapeando-os duas vezes. Em uma das classes devemos adicionar o atributo mappedBy na anotao @O NE T O O NE. O valor do MAPPED B Y o nome do atributo que expressa o mesmo relacionamento na outra entidade.
1 2 3 4 5 6 7 8 9 10 11 @Entity class Governador { @Id @GeneratedValue private Long id; @OneToOne(mappedBy="governador") private Estado estado; // GETTERS E SETTERS }

2.12

Objetos Embutidos

Suponha que no nosso domnio existe uma entidade chamada Pessoa. Toda pessoa possui um endereo que formado por pas, estado, cidade, logradouro, nmero, complemento e CEP. Para melhorar a organizao da nossa aplicao podemos decidir criar duas classes: Pessoa e Endereco 21 K19 Treinamentos

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 @Entity class Pessoa { @Id @GeneratedValue private Long id; private String nome; private Calendar nascimento; private Endereco endereco; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

class Endereco { private String pais; private String estado; private String cidade; private String logradouro; private int numero; private String complemento; private int cep; }

Muitas vezes no queremos mapear a classe E NDERECO para uma outra tabela. Normalmente, queremos que os dados dos endereos sejam guardados na mesma tabela que guarda os dados das pessoas. Nesse caso no devemos aplicar a anotao @E NTITY na classe E N DERECO . No lugar da anotao @E NTITY devemos aplicar a anotao @Embeddable. Alm disso, no devemos denir uma chave para a classe E NDERECO pois ela no dene uma entidade.
1 2 @Embeddable class Endereco {

2.13

Exerccios

7. Implemente duas entidades no pacote modelo do projeto Mapeamento: E STADO e G O VERNADOR .


1 2 3 4 5 6 7 8 9 10 @Entity public class Governador { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

www.k19.com.br

22

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Estado { @Id @GeneratedValue private Long id; private String nome; @OneToOne private Governador governador; // GETTERS AND SETTERS }

8. Adicione um governador e um estado atravs do seguinte teste.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

public class AdicionaEstadoGovernador { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Governador g = new Governador(); g.setNome("Rafael Cosentino"); Estado e = new Estado(); e.setNome("So Paulo"); e.setGovernador(g); manager.persist(g); manager.persist(e); manager.getTransaction().commit(); manager.close(); factory.close(); } }

9. Abra o MySQL Query Browser e observe as propriedades da tabela Estado e da Governador da base de dados K21_mapeamento. 10. Implemente duas entidades no pacote modelo do projeto Mapeamento: D EPARTA MENTO e F UNCIONARIO .
1 2 3 4 5 6 7 8 9 10 @Entity public class Funcionario { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

23

K19 Treinamentos

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Departamento { @Id @GeneratedValue private Long id; private String nome; @OneToMany private Collection<Funcionario> funcionarios = new ArrayList<Funcionairo>(); // GETTERS AND SETTERS }

11. Adicione um departamento e um funcionairo atravs do seguinte teste.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

public class AdicionaDepartamentoFuncionario { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Funcionario f = new Funcionario(); f.setNome("Rafael Cosentino"); Departamento d = new Departamento(); d.setNome("Financeiro"); d.getFuncionarios().add(f); manager.persist(f); manager.persist(d); manager.getTransaction().commit(); manager.close(); factory.close(); } }

12. Abra o MySQL Query Browser e observe as propriedades da tabela Departamento, da Funcionario e da Departamento_Funcionario da base de dados K21_mapeamento. 13. Implemente duas entidades no pacote modelo do projeto Mapeamento: P EDIDO e C LI ENTE.
1 2 3 4 5 6 7 8 9 10 @Entity public class Cliente { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

www.k19.com.br

24

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Entity public class Pedido { @Id @GeneratedValue private Long id; @Temporal(TemporalType.DATE) private Calendar data; @ManyToOne private Cliente cliente; // GETTERS AND SETTERS }

14. Adicione um cliente e um departamento atravs do seguinte teste.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class AdicionaPedidoCliente { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Cliente c = new Cliente(); c.setNome("Rafael Cosentino"); Pedido p = new Pedido(); p.setData(Calendar.getInstance()); p.setCliente(c); manager.persist(c); manager.persist(p); manager.getTransaction().commit(); manager.close(); factory.close(); } }

15. Abra o MySQL Query Browser e observe as propriedades da tabela Cliente da Pedido da base de dados K21_mapeamento. 16. Implemente duas entidades no pacote modelo do projeto Mapeamento: L IVRO e AU TOR .
1 2 3 4 5 6 7 8 9 10 @Entity public class Autor { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

25

K19 Treinamentos

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Livro { @Id @GeneratedValue private Long id; private String nome; @ManyToMany private Collection<Autor> autores = new ArrayList<Autor>(); // GETTERS AND SETTERS }

17. Adicione um livro e um autor atravs do seguinte teste.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class AdicionaLivroAutor { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Autor a = new Autor(); a.setNome("Rafael Cosentino"); Livro l = new Livro(); l.setNome("JPA2"); l.getAutores().add(a); manager.persist(a); manager.persist(l); manager.getTransaction().commit(); manager.close(); factory.close(); } }

18. Abra o MySQL Query Browser e observe as propriedades da tabela Livro, da Autor e da Livro_Autor da base de dados K21_mapeamento. 19. (Opcional) Crie uma classe para modelar endereos no pacote modelo.
1 2 3 4 5 6 7 8 9 10 11 12 public class Endereco { private String estado; private String cidade; private String logradouro; private int numero; // GETTERS AND SETTERS }

www.k19.com.br

26

Mapeamento 20. (Opcional) Adicione um atributo na classe F UNCIONARIO do tipo E NDERECO.


1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Funcionario { @Id @GeneratedValue private Long id; private String nome; @Embedded private Endereco endereco; // GETTERS AND SETTERS }

21. (Opcional) Altere a classe A DICIONA D EPARTAMENTO F UNCIONARIO e depois executea.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class AdicionaDepartamentoFuncionario { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Endereco e = new Endereco(); e.setEstado("So Paulo"); e.setCidade("So Paulo"); e.setLogradouro("Av. Bigadeiro Faria Lima"); e.setNumero(1571); Funcionario f = new Funcionario(); f.setNome("Rafael Cosentino"); f.setEndereco(e); Departamento d = new Departamento(); d.setNome("Financeiro"); d.getFuncionarios().add(f); manager.persist(f); manager.persist(d); manager.getTransaction().commit(); manager.close(); factory.close(); } }

2.14

Herana

O mapeamento objeto relacional descreve como os conceitos de orientao a objetos so denidos no banco de dados atravs dos conceitos do modelo entidade relacionamento. De todos os conceitos de orientao a objetos, um dos mais complexos de se mapear o de Herana. A especicao JPA dene trs estratgia para realizar o mapeamento de herana. 27 K19 Treinamentos

Mapeamento Single Table Joined Table Per Class

2.14.1

Single Table

A estratgia Single Table a mais comum e a que possibilita melhor desempenho em relao a velocidade das consultas. Nessa estratgia, a super classe deve ser anotada com @I NHE RITANCE ( STRATEGY =I NHERITANCE T YPE .SINGLE_TABLE). O provedor JPA criar apenas uma tabela com o nome da super classe para armazenar os dados dos objetos criados a partir da super classe ou das sub classes. Todos os atributos da super classe e os das sub classes sero mapeados para colunas dessa tabela. Alm disso, uma coluna especial chamada DTYPE ser utilizada para identicar a classe do objeto correspondente ao registro.
1 2 3 4 5 6 7 8 9 10 @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) public class Pessoa { @Id @GeneratedValue private Long id; private String nome; }

1 2 3 4

@Entity public class PessoaJuridica extends Pessoa{ private String cnpj; }

1 2 3 4

@Entity public class PessoaFisica extends Pessoa{ private String cpf; }

A desvantagem da Single Table consumo desnecessrio de espao j que nem todos os campos so utilizados para todos os registros. Por exemplo, se uma pessoa jurdica for cadastrada o campo CPF no seria utilizado. Da mesma forma, que se uma pessoa fsica for cadastrada o campo CNPJ no seria utilizado.

2.14.2

Joined

Nessa estratgia, uma tabela para cada classe da hierarquia criada. Em cada tabela, apenas os campos referentes aos atributos da classe correspondente so criados. Para relacionar os registros das diversas tabelas e remontar os objetos quando uma consulta for realizada, as tabelas www.k19.com.br 28

Mapeamento correspondentes s sub classes possuem chaves estrangeiras vinculadas tabela correspondente super classe.
1 2 3 4 5 6 7 8 9 10 @Entity @Inheritance(strategy=InheritanceType.JOINED) public class Pessoa { @Id @GeneratedValue private Long id; private String nome; }

1 2 3 4

@Entity public class PessoaJuridica extends Pessoa{ private String cnpj; }

1 2 3 4

@Entity public class PessoaFisica extends Pessoa{ private String cpf; }

O consumo de espao utilizando a estratgia Joined menor do que utilizando a estratgia Single Table. Contudo, as consultas so mais lentas pois necessrio realizar operaes de join para recuperar os dados dos objetos.

2.14.3

Table Per Class

Nessa estratgia, uma tabela para cada classe concreta da hierarquia criada. Contudo, os dados de um objeto no so colocados em tabelas diferentes. Dessa forma, para remontar um objeto no necessrio realizar operaes de join. A desvantagem desse modo que no existe um vnculo explcito no banco de dados entres as tabelas correspondentes as classes da hierarquia.
1 2 3 4 5 6 7 8 9 @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Pessoa { @Id private Long id; private String nome; }

29

K19 Treinamentos

Mapeamento
1 2 3 4 @Entity public class PessoaJuridica extends Pessoa{ private String cnpj; }

1 2 3 4

@Entity public class PessoaFisica extends Pessoa{ private String cpf; }

Na estratgia Table Per Class, no podemos utilizar a gerao automtica de chave primrias simples e numricas.

2.15

Exerccios

22. Adicione uma classe chamada Pessoa no pacote modelo.


1 2 3 4 5 6 7 8 9 10 11 @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) public class Pessoa { @Id @GeneratedValue private Long id; private String nome; //GETTERS AND SETTERS }

23. Faa a classe PessoaJuridica no pacote modelo.


1 2 3 4 5 6 @Entity public class PessoaJuridica extends Pessoa{ private String cnpj; //GETTERS AND SETTERS }

24. Faa a classe PessoaFisica no pacote modelo.


1 2 3 4 5 6 @Entity public class PessoaFisica extends Pessoa{ private String cpf; //GETTERS AND SETTERS }

25. Crie um teste para adicionar pessoas. www.k19.com.br 30

Mapeamento
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class AdicionaPessoa { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory(" K21_mapeamento"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Pessoa p1 = new Pessoa(); p1.setNome("Marcelo"); PessoaFisica p2 = new PessoaFisica(); p2.setNome("Rafael"); p2.setCpf("1234"); PessoaJuridica p3 = new PessoaJuridica(); p3.setNome("K19"); p3.setCnpj("567788"); manager.persist(p1); manager.persist(p2); manager.persist(p3); manager.getTransaction().commit(); manager.close(); factory.close(); } }

31

K19 Treinamentos

Mapeamento

www.k19.com.br

32

Captulo 3 Entity Manager


As instncias das entidades do JPA so administradas pelos Entity Managers. As duas principais responsabilidades dos Entity Managers so: gerenciar o estado dos objetos e sincronizar os dados da aplicao e do banco de dados.

3.1

Estados

necessrio conhecer o ciclo de vida das entidades para saber como os objetos so administrados pelos Entity Managers. Uma instncia de uma entidade pode passar pelos seguintes estados: Novo(New) : Um objeto no estado new no possui uma identidade (chave) e no est associado a um Entity Manager. O contedo desse objeto no sincronizado com o banco de dados. Toda instncia de uma entidade que acabou de ser criada com o comando NEW se encontra no estado new do JPA. Administrado(Managed) : Um objeto no estado managed possui uma identidade e est associado a um Entity Manager que mantm o contedo desse objeto sincronizado com o banco de dados. Desvinculado(Detached) : Um objeto no estado detached possui uma identidade e no est associado a um Entity Manager. Dessa forma, o contedo desse objeto no sincronizado com o banco de dados. Removido(Removed) : Um objeto no estado removed possui uma identidade e est associado a um Entity Manager. O contedo desse objeto ser removido do banco de dados.

3.2

Sincronizao com o Banco de Dados

As modicaes realizadas no estado dos objetos managed so propagadas para o banco de dados. Os registros referentes aos objetos em estado removed so apagados do banco de dados. Essa sincronizao responsabilidade dos provedores de JPA. De acordo com a especicao, uma sincronizao s pode ocorrer se uma transao estiver ativa. 33

Entity Manager
1 2 3 manager.getTransaction().begin(); // nesse trecho pode acorrer sincronizaes manager.getTransaction().commit();

3.2.1

Flush Mode

H duas polticas adotadas pelos provedores em relao s sincronizaes: FlushModeType.AUTO: As sincronizaes ocorrem antes de uma consulta ou em chamadas dos mtodos COMMIT () ou FLUSH (). FlushModeType.COMMIT: As sincronizaes ocorrem em chamadas dos mtodos MIT () ou FLUSH ().
COM -

De acordo com a especicao JPA, no F LUSH M ODE T YPE .AUTO, os provedores devem garantir que as consultas considerem alteraes realizadas nas entidades. Por isso, os provedores realizam uma sincronizao antes de uma consulta. Por outro lado, no F LUSH M O DE T YPE .COMMIT, a especicao no determina a mesma responsabilidade aos provedores. Por isso, nesse modo, eles no realizam uma sincronizao antes de uma consulta. Em relao a performance, o F LUSH M ODE T YPE .COMMIT mais eciente pois realiza menos sincronizaes com o banco de dados do que o F LUSH M ODE T YPE .AUTO. Contudo, muitas vezes, o F LUSH M ODE T YPE .AUTO necessrio para garantir a informao mais atualizada seja obtida nas consultas. Podemos congurar o ush mode no nvel de um Entity Manager afetando o comportamento em todas as consultas realizadas atravs desse Entity Manager ou congurar apenas para uma consulta.
1 manager.setFlushMode(FlushModeType.COMMIT);

query.setFlushMode(FlushModeType.AUTO);

OBS: O tipo padro de ush mode o AUTO de acordo com a especicao JPA.

3.3

Transies

Uma instncia de uma entidade pode mudar de estado. Veremos a seguir as principais transies.

3.3.1

New -> Managed

Um objeto no estado new passa para o estado managed quando utilizamos o mtodo persist() dos Entity Managers. O estado desse objeto ser armazenado no banco de dados e ele ganhar uma identidade. www.k19.com.br 34

Entity Manager
1 2 3 4 5 6 7 8 9 10 @Entity class Pessoa { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

1 2 3 4 5 6 7

manager.getTransaction().begin(); Pessoa p = new Pessoa(); p.setNome("Rafael Cosentino"); manager.persist(); manager.getTransaction().commit();

O contedo do objeto ser armazenado no banco de dados quando o provedor realizar uma sincronizao. Veja a seo sobre sincronizao.

3.3.2

BD -> Managed

Quando dados so recuperados do banco de dados, o provedor do JPA cria objetos para armazenar as informaes e esses objetos so considerados managed.
1 Pessoa p = manager.find(Pessoa.class, 1L);

Pessoa p = manager.getReference(Pessoa.class, 1L);

1 2

Query query = manager.createQuery("select p from Pessoa p"); List<Pessoa> lista = query.getResultList();

3.3.3

Managed -> Detached

Quando no queremos mais que um objeto no estado managed seja administrado, podemos desvincul-lo do seu Entity Manager tornando-o detached. Dessa forma, o contedo desse objeto no ser mais sincronizado com o banco de dados. Para tornar apenas um objeto detached, devemos utilizar o mtodo detach():
1 2 Pessoa p = manager.find(Pessoa.class, 1L); manager.detach(p);

35

K19 Treinamentos

Entity Manager Para tornar detached todos os objetos administrados por um Entity Manager, devemos utilizar o mtodo clear().
1 manager.clear();

Outra maneira de tornar detached todos os objetos administrados por um Entity Manager utilizar o mtodo close().
1 manager.close();

3.3.4

Detached -> Managed

O estado de um objeto detached pode ser propagado para um objeto managed com a mesma identidade para que os dados sejam sincronizados com o banco de dados. Esse processo realizado pelo mtodo merge().
1 Pessoa pessoaManaged = manager.merge(pessoaDetached);

3.3.5

Managed -> Removed

Quando um objeto managed se torna detached, os dados correspondentes a esse objeto no so apagados do banco de dados. Agora, quando utilizamos o mtodo remove() marcamos um objeto para ser removido do banco de dados.
1 2 Pessoa p = manager.find(Pessoa.class, 1L); manager.remove(p);

O contedo do objeto ser removido no banco de dados quando o provedor realizar uma sincronizao. Veja a seo sobre sincronizao.

3.3.6

Managed -> Managed

O contedo de um objeto no estado managed pode car desatualizado em relao ao banco de dados se algum ou alguma aplicao alterar os dados na base de dados. Para atualizar um objeto managed com os dados do banco de dados, devemos utilizar o mtodo refresh().
1 2 Pessoa p = manager.find(Pessoa.class, 1L); manager.refresh(p);

www.k19.com.br

36

Entity Manager

3.4

Regras de Transies

A especicao determina um grande conjunto de regras burocrticas em relao s transies. Consulte essas regras na seo 3.8 da JSR 317 - Java Persistence API, Version 2.0 http: //jcp.org/aboutJava/communityprocess/final/jsr317/index.html.

3.5

Exerccios

1. Crie um projeto no eclipse chamado EntityManager. Copie a pasta lib do projeto JPA2Hibernate para o projeto EnityManager. Depois selecione todos os jars e os adicione no classpath. 2. Abra o MySQL Query Browser e apague a base de dados K21_entity_manager se existir. Depois crie a base de dados K21_entity_manager. 3. Copie a pasta META-INF do projeto JPA2-Hibernate para dentro da pasta src do projeto EntityManager. Altere o arquivo persistence.xml do projeto EntityManager, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_entity_manager" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver "/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="root"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_entity_manager"/> </properties> </persistence-unit> </persistence>

4. Crie um pacote chamado modelo no projeto EntityManager e adicione a seguinte classe:


1 2 3 4 5 6 7 8 9 10 @Entity public class Pessoa { @Id @GeneratedValue private Long id; private String nome; // GETTERS E SETTERS }

37

K19 Treinamentos

Entity Manager 5. Teste persistir objetos atravs de um Entity Manager. Crie uma classe chamada TestePersist dentro de um pacote chamado testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

public class TestePersist { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); // ABRINDO A TRASACAO manager.getTransaction().begin(); // OBJETO NO ESTADO NEW Pessoa p = new Pessoa(); p.setNome("Rafael Cosentino"); // OBJETO NO ESTADO MANAGED manager.persist(p); // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager.getTransaction().commit(); System.out.println("Pessoa id: " + p.getId()); manager.close(); factory.close(); } }

Execute e consulte o banco de dados! 6. Teste buscar objetos atravs de um Entity Manager dado a identidade dos objetos. Crie uma classe chamada TesteFind dentro de um pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

public class TesteFind { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); // OBJETO NO ESTADO MANAGED Pessoa p = manager.find(Pessoa.class, 1L); System.out.println("Id: " + p.getId()); System.out.println("Nome: " + p.getNome()); manager.close(); factory.close(); } }

Execute e consulte o banco de dados! 7. Teste alterar objetos no estado managed e depois faa um sincronizao com o banco de dados atravs de uma chamada ao mtodo COMMIT (). Crie uma classe chamada TesteManaged dentro de um pacote testes. www.k19.com.br 38

Entity Manager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TesteManaged { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); // OBJETO NO ESTADO MANAGED Pessoa p = manager.find(Pessoa.class, 1L); // ALTERANDO O CONTEUDO DO OBJETO p.setNome("Marcelo Martins"); // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e consulte o banco de dados! 8. Teste alterar objetos no estado detached e depois faa um sincronizao com o banco de dados atravs de uma chamada ao mtodo COMMIT (). Crie uma classe chamada TesteDetached dentro de um pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TesteDetached { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); // OBJETO NO ESTADO MANAGED Pessoa p = manager.find(Pessoa.class, 1L); // OBJETO NO ESTADO DETACHED manager.detach(p); // ALTERANDO O CONTEUDO DO OBJETO p.setNome("Marcelo Martins"); // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e consulte o banco de dados!

3.6

LAZY e EAGER

Como os Entity Managers administram as instncias das entidades eles so responsveis pelo carregamento do estado dos objetos. H dois modos de carregar os dados de um objeto: 39 K19 Treinamentos

Entity Manager LAZY ou EAGER. No modo LAZY, o provedor posterga ao mximo a busca dos dados no banco de dados. No modo EAGER, o provedor busca imediatamente os dados no banco de dados.

3.6.1

nd() VS getReference()

Tanto o mtodo FIND () quanto o mtodo GET R EFERENCE () permitem que a aplicao obtenha instncias das entidades a partir das identidade dos objetos. A diferena entre eles que o FIND () tem comportamento EAGER e o GET R EFERENCE () tem comportamento LAZY.
1 2 Pessoa p = manager.find(Pessoa.class, 1L); // o objeto j est carregado

1 2 3 4

Pessoa p = manager.getReference(Pessoa.class, 1L); // o objeto no est carregado ainda String nome = p.getNome(); // agora o objeto est carregado

3.6.2

Fetch Type - Tipos Bsicos

A escolha do modo de carregamento EAGER ou LAZY pode ser realizada no nvel dos atributos bsicos. Por padro, os atributos bsicos so carregados em modo EAGER. No possvel forar que o modo de carregamento de um atributo seja LAZY. O que possvel fazer indicar aos provedores de JPA que seria interessante utilizar o modo LAZY para determinados atributos. Contudo, os provedores podem no aceitar essa indicao e utilizar o modo EAGER. De qualquer forma, podemos indicar o modo LAZY para atributos bsicos atravs da anotao @Basic e da propriedade fetch.
1 2 3 4 @Basic(fetch=FetchType.LAZY) protected String getNome() { return nome; }

Obs: O modo LAZY para atributos bsicos s pode ser aceito pelos provedores se o modo de acesso for Property Access.

3.6.3

Fetch Type - Relacionamentos

Podemos denir o modo de carregamento que desejamos utilizar para os relacionamentos das entidades. Por exemplo, suponha um relacionamento unidirecional entre estados e governadores. www.k19.com.br 40

Entity Manager
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id; @OneToOne private Governador governador; }

1 2 3 4 5 6

@Entity class Governador { @Id @GeneratedValue private Long id; }

Por padro, quando os dados de um estado so recuperados do banco de dados, os dados do governador associado a esse estado tambm recuperado. Em outras palavras, o modo de carregamento padro do atributo que estabelece o relacionamento entre estados e governadores EAGER. Podemos alterar esse comportamento padro aplicando a propriedade fetch na anotao @OneToOne.
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id; @OneToOne(fetch=FetchType.LAZY) private Governador governador; }

O modo de carregamento dos relacionamentos do tipo One To One e Many To One por padro EAGER. O modo de carregamento dos relacionamentos do tipo One To Many e Many To Many por padro LAZY. Lembrando que o modo de carregamento pode ser denido com a propriedade fetch.
1 2 3 4 @OneToOne(fetch=FetchType.LAZY) @ManyToOne(fetch=FetchType.LAZY) @OneToMany(fetch=FetchType.EAGER) @ManyToMany(fetch=FetchType.EAGER)

3.7

Lazy Initialization

No modo de carregamento LAZY, o provedor JPA posterga ao mximo a busca dos dados no banco de dados. O carregamento s poder ser feito posteriormente se o Entity Manager correspondente estiver aberto. Se os dados de um objeto ainda no foram carregados e a aplicao fechar o Entity Manager correspondente, o provedor lanar uma exception. 41 K19 Treinamentos

Entity Manager

3.8

Persistence Context ou Cache de Primeiro Nvel

Um objeto j carregado por um Entity Manager mantido no Persistence Context (Cache de Primeiro Nvel, na nomenclatura do Hibernate). Cada Entity Manager possui o seu prprio Persistence Context. Se a aplicao buscar um objeto atravs de um Entity Manager e ele j estiver carregado no Persistence Context correspondente, a busca no ser realizado no banco de dados evitando assim uma consulta.

3.9

Exerccios

9. Acrescente duas propriedades no arquivo de congurao do JPA (persistence.xml) para indicar ao Hibernate que desejamos ver as consultas no console.

1 2

<property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" />

10. Teste o comportamento do mtodo de busca nd(). Crie um classe chamada TesteFindEager no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14

public class TesteFindEager { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); System.out.println("-----------CHAMANDO O FIND------------"); Pessoa p = manager.find(Pessoa.class, 1L); System.out.println("-----------FEZ O SELECT---------------"); manager.close(); factory.close(); } }

Execute e veja a sada!

11. Teste o comportamento do mtodo de busca getReference(). Crie um classe chamada TesteGetReferenceLazy no pacote testes. www.k19.com.br 42

Entity Manager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TesteGetReferenceLazy { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); System.out.println("-----------CHAMANDO O GETREFERENCE----"); Pessoa p = manager.getReference(Pessoa.class, 1L); System.out.println("-----------NAO FEZ O SELECT-----------"); manager.close(); factory.close(); } }

Execute e veja a sada! 12. Teste o problema de Lazy Initialization. Crie um classe chamada TesteLazyInitialization no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

public class TesteLazyInitialization { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); // OBJETO CARREGADO EM MODO LAZY Pessoa p = manager.getReference(Pessoa.class, 1L); manager.close(); factory.close(); System.out.println(p.getNome()); } }

Execute e veja a sada! 13. Crie duas classes para modelar governadores e estados, estabelecendo um relacionamento One to One entre essas entidades.

1 2 3 4 5 6 7 8 9 10 11 12 13

@Entity public class Estado { @Id @GeneratedValue private Long id; private String nome; @OneToOne private Governador governador; // GETTERS AND SETTERS }

43

K19 Treinamentos

Entity Manager
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Governador { @Id @GeneratedValue private Long id; private String nome; @OneToOne(mappedBy="governador") private Estado estado; // GETTERS AND SETTERS }

14. Adicione um governador e um estado. Crie uma classe chamada AdicionaGovernadorEstado no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class AdicionaGovernadorEstado { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Governador governador = new Governador(); governador.setNome("Rafael Cosentino"); Estado estado = new Estado(); estado.setNome("So Paulo"); governador.setEstado(estado); estado.setGovernador(governador); manager.persist(estado); manager.persist(governador); manager.getTransaction().commit(); manager.close(); factory.close(); } }

15. Teste o carregamento EAGER no relacionamento One to One entre estados e governadores. Crie uma classe chamada TesteCarregamentoRelacionamento no pacote testes.
1 2 3 4 5 6 7 8 public class TesteCarregamentoRelacionamento { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory(" K21_entity_manager"); EntityManager manager = factory.createEntityManager(); Estado estado = manager.find(Estado.class, 1L); } }

Observe a sada no console para vericar o carregamento tanto do estado quanto www.k19.com.br 44

Entity Manager do governador 16. Altere a poltica padro do carregamento do governador adicionando a propriedade FETCH na anotao @O NE T O O NE na classe E STADO.
1 2 @OneToOne(fetch=FetchType.LAZY) private Governador governador;

17. Execute novamente a classe T ESTE C ARREGAMENTO R ELACIOMENTO e observe a sada do console para vericar que agora somente o estado carregado. 18. (Opcional) Faa acontecer o problema de Lazy Initialization no exemplo de estados e governadores. 19. Verique o comportamento dos Entity Managers ao buscar duas vezes o mesmo objeto. Crie uma classe chamada TestePersistenceContext no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 public class TestePersistenceContext { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_entity_manager"); EntityManager manager = factory.createEntityManager(); System.out.println("------------------PRIMEIRO FIND-----------------"); Estado estado = manager.find(Estado.class, 1L); System.out.println("------------------SEGUNDO FIND------------------"); estado = manager.find(Estado.class, 1L); } }

Execute e observe a sada no console para vericar que o provedor s realiza uma busca

3.10

Cascade

As operaes dos Entity Managers so realizadas somente no objeto passado como parmetro para o mtodo que implementa a operao. Por exemplo, suponha o relacionamento entre estados e governadores.
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Estado { @Id @GeneratedValue private Long id; private String nome; @OneToOne private Governador governador; // GETTERS AND SETTERS }

45

K19 Treinamentos

Entity Manager
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Governador { @Id @GeneratedValue private Long id; private String nome; @OneToOne(mappedBy="governador") private Estado estado; // GETTERS AND SETTERS }

Suponha que um objeto da classe E STADO e outro da classe G OVERNADOR sejam criados e associados. Se apenas um dos objetos for persistido um erro ocorrer na sincronizao com o banco de dados.
1 2 3 4 5 6 7 8 9 10 11 12 Governador governador = new Governador(); governador.setNome("Rafael Cosentino"); Estado estado = new Estado(); estado.setNome("So Paulo"); governador.setEstado(estado); estado.setGovernador(governador); manager.getTransaction().begin(); manager.persist(estado); manager.getTransaction().commit();

Para evitar o erro, os dois objetos precisam ser persistidos.


1 2 3 4 manager.getTransaction().begin(); manager.persist(estado); manager.persist(governador); manager.getTransaction().commit();

Ou ento podemos congurar o relacionamento entre estados e governadores com a propriedade cascade para a operao PERSIST.
1 2 @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST) private Governador governador;

A propriedade cascade pode ser utilizada para as outras operaes dos Entity Managers. CascadeType.PERSIST CascadeType.DETACH CascadeType.MERGE CascadeType.REFRESH CascadeType.REMOVE www.k19.com.br 46

Entity Manager CascadeType.ALL Alm disso, a propriedade cascade unidirecional. Dessa forma, nos relacionamentos bidirecionais para ter o comportamente do cascade nas duas direes necessrio utilizar a propriedade cacasde nas duas entidades.

3.11

Exerccios

20. Tente adicionar um governador e um estado. Crie uma classe chamada TesteCascade no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class TesteCascade { public static void main(String[] args) { EntityManagerFactory factory = Persistence.createEntityManagerFactory(" K21_entity_manager"); EntityManager manager = factory.createEntityManager(); Governador governador = new Governador(); governador.setNome("Rafael Cosentino"); Estado estado = new Estado(); estado.setNome("So Paulo"); governador.setEstado(estado); estado.setGovernador(governador); manager.getTransaction().begin(); manager.persist(estado); manager.getTransaction().commit(); } }

Execute e observe o erro 21. Modique a classe Estado para congurar a propriedade cascade no relacionamento com governadores.
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Estado { @Id @GeneratedValue private Long id; private String nome; @OneToOne(cascade=CascadeType.PERSIST) private Governador governador; // GETTERS AND SETTERS }

22. Execute a classe TesteCascade e observe que no ocorre o mesmo erro que aconteceu anteriormente.

47

K19 Treinamentos

Entity Manager

www.k19.com.br

48

Captulo 4 JPQL
A capacidade que os bancos de dados possuem de realizar consultas complexas um forte argumento para utiliz-los. A denio e os resultados das consultas nos banco de dados so fortemente baseados ao modelo relacional. Por outro lado, natural que as aplicaes baseadas no modelo orientado a objetos desejem que a denio e os resultados das consultas sejam baseados no paradigma orientado a objetos. Por isso, os provedores de JPA oferecem mecanismos para realizar consultas de uma maneira orientada a objetos. Para ser mais exato, a especicao JPA 2 dene dois mecanismos para realizar consultas orientadas a objetos: o primeiro utiliza uma linguagem especca para consultas chamada JPQL (Java Persistence Query Language) e o segundo basicamente uma biblioteca Java para consultas. Nesse captulo mostraremos o funcionamento da JPQL.

4.1

Consultas Dinmicas

Consultas em JPQL podem ser denidas em qualquer classe Java, dentro de um mtodo por exemplo. Para criar uma consulta devemos utilizar o mtodo createQuery() passando uma string com o cdigo JPQL. Consultas criadas dessa maneira so chamadas de consultas dinmicas.
1 2 3 4 public void umMetodoQualquer() { String jpql = "SELECT p FROM Pessoa p"; Query query = manager.createQuery(jpql); }

Apesar da exibilidade, criar consultas dinmicas pode prejudicar a performance da aplicao. Por exemplo, se uma consulta dinmica criada dentro de um mtodo toda vez que esse mtodo for chamado o cdigo JPQL dessa consulta ser processado pelo provedor. Uma alternativa menos exvel porm mais performtica s consultas dinmicas so as Named Queries.

4.2

Named Query

Diferentemente de uma consulta dinmica, uma Named Query processado apenas no momento da criao da fbrica de Entity Manager. Alm disso, os provedores JPA podem mapear 49

JPQL as Named Queries para Stored Procedures precompiladas do banco de dados melhorando a performance das consultas. As Named Queries so denidas atravs de anotaes nas classes que implementam as entidades. Podemos aplicar a anotao @NamedQuery quando queremos denir apenas uma consulta ou a anotao @NamedQueries quando queremos denir vrias consultas.
1 2 @NamedQuery(name="Pessoa.findAll", query="SELECT p FROM Pessoa p") class Pessoa

1 2 3 4 5

@NamedQueries({ @NamedQuery(name="Pessoa.findAll", query="SELECT p FROM Pessoa p"), @NamedQuery(name="Pessoa.count", query="SELECT COUNT(p) FROM Pessoa p") }) class Pessoa

Para executar uma Named Query, devemos utilizar o mtodo createNamedQuery().


1 2 3 4 public void umMetodoQualquer() { Query query = manager.createNamedQuery("Pessoa.findAll"); List<Pessoa> pessoas = query.getResultList(); }

Os nomes das Named Queries devem ser nicos no contexto da aplicao. Caso contrrio, o provedor lanar uma exception na criao da fbrica de Entity Managers. Dessa forma, a conveno utilizar o nome da classe na qual a Named Query est denida como prexo do nome da consulta.

4.3

Parmetros

Para tornar as consultas em JPQL mais genricas e evitar problemas com SQL Injection, devemos parametriz-las. Adicionar um parmetro em uma consulta simples, basta utilizar caractere : seguido do nome do argumento.
1 2 @NamedQuery(name="Pessoa.findByIdade", query="SELECT p FROM Pessoa p WHERE p.idade > :idade")

Antes de executar uma consulta com parmetros, devemos denir os valores dos argumentos.
1 2 3 4 5 public void umMetodoQualquer() { Query query = manager.createNamedQuery("Pessoa.findByIdade"); query.setParameter("idade", 18); List<Pessoa> pessoasComMaisDe18 = query.getResultList(); }

possvel tambm adicionar parmetros em uma consulta de maneira ordinal basta utilizar www.k19.com.br 50

JPQL o caractere ? seguido de um nmero.


1 2 @NamedQuery(name="Pessoa.findByIdade", query="SELECT p FROM Pessoa p WHERE p.idade > ?1")

1 2 3 4 5

public void umMetodoQualquer() { Query query = manager.createNamedQuery("Pessoa.findByIdade"); query.setParameter(1, 18); List<Pessoa> pessoasComMaisDe18 = query.getResultList(); }

4.4

Exerccios

1. Crie um projeto no eclipse chamado JPQL. Copie a pasta lib do projeto EntityManager para o projeto JPQL. Depois selecione todos os jars e os adicione no classpath. 2. Abra o MySQL Query Browser e apague a base de dados K21_jpql se existir. Depois crie a base de dados K21_jpql. 3. Copie a pasta META-INF do projeto EntityManager para dentro da pasta src do projeto JPQL. Altere o arquivo persistence.xml do projeto JPQL, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

<?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_jpql" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver " /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="root" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_jpql" /> </properties> </persistence-unit> </persistence>

4. Crie um pacote chamado modelo no projeto JPQL e adicione as seguintes classes: 51 K19 Treinamentos

JPQL
1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Autor { @Id @GeneratedValue private Long id; private String nome; @ManyToMany private Collection<Livro> livros = new ArrayList<Livro>(); // GETTERS E SETTERS }

1 2 3 4 5 6 7 8 9 10 11 12

@Entity public class Livro { @Id @GeneratedValue private Long id; private String nome; private Double preco; // GETTERS E SETTERS }

5. Carregue o banco de dados com as informaes de alguns livros e autores. Adicione a seguinte classe em um novo pacote chamado testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class PopulaBanco { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Livro livro1 = new Livro(); livro1.setNome("The Battle for Your Mind"); livro1.setPreco(20.6); manager.persist(livro1); Livro livro2 = new Livro(); livro2.setNome("Differentiate or Die"); livro2.setPreco(15.8); manager.persist(livro2); Livro livro3 = new Livro(); livro3.setNome("How to Transform Your Ideas"); livro3.setPreco(32.7); manager.persist(livro3); Livro livro4 = new Livro(); livro4.setNome("Digital Fortress"); livro4.setPreco(12.9); manager.persist(livro4); Livro livro5 = new Livro(); livro5.setNome("Marketing in an Era of Competition, Change and Crisis"); livro5.setPreco(26.8); manager.persist(livro5);

www.k19.com.br

52

JPQL
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 Autor autor1 = new Autor(); autor1.setNome("Patrick Cullen"); autor1.getLivros().add(livro2); autor1.getLivros().add(livro4); manager.persist(autor1); Autor autor2 = new Autor(); autor2.setNome("Fraser Seitel"); autor2.getLivros().add(livro3); manager.persist(autor2); Autor autor3 = new Autor(); autor3.setNome("Al Ries"); autor3.getLivros().add(livro1); manager.persist(autor3); Autor autor4 = new Autor(); autor4.setNome("Jack Trout"); autor4.getLivros().add(livro1); autor4.getLivros().add(livro2); autor4.getLivros().add(livro5); manager.persist(autor4); Autor autor5 = new Autor(); autor5.setNome("Steve Rivkin"); autor5.getLivros().add(livro2); autor5.getLivros().add(livro3); autor5.getLivros().add(livro5); manager.persist(autor5); manager.getTransaction().commit(); manager.close(); factory.close(); } }

6. Teste as consultas dinmicas com JPQL. Crie a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

public class TesteConsultaDinamicas { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); Query query = manager.createQuery("select a from Autor a"); List<Autor> autores = query.getResultList(); for (Autor autor : autores) { System.out.println("Autor: " + autor.getNome()); Collection<Livro> livros = autor.getLivros(); for (Livro livro : livros) { System.out.println("Livro: " + livro.getNome()); System.out.println("Preo: " + livro.getPreco()); System.out.println(); } System.out.println(); } manager.close(); factory.close(); } }

53

K19 Treinamentos

JPQL Execute e observe que as consultas so realizadas aos poucos devido ao carregamento em modo LAZY 7. Para testar as Named Queries, acrescente a anotao @NAMED Q UERY na classe AUTOR.
1 2 3 4 5 @Entity @NamedQuery(name="Autor.findAll", query="select a from Autor a") public class Autor { ... }

8. Na sequncia crie um teste da Named Query denida no exerccio anterior.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class TesteNamedQuery { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); Query query = manager.createNamedQuery("Autor.findAll"); List<Autor> autores = query.getResultList(); for (Autor autor : autores) { System.out.println("Autor: " + autor.getNome()); Collection<Livro> livros = autor.getLivros(); for (Livro livro : livros) { System.out.println("Livro: " + livro.getNome()); System.out.println("Preo: " + livro.getPreco()); System.out.println(); } System.out.println(); } manager.close(); factory.close(); } }

Execute e observe que as consultas so realizadas aos poucos devido ao carregamento em modo LAZY 9. Acrescente a anotao @NAMED Q UERY na classe L IVRO para denir uma consulta por preo mnimo utilizando parmetros.
1 2 3 4 5 6 @Entity @NamedQuery(name="Livro.findByPrecoMinimo", query="select livro from Livro livro where livro.preco >= :preco") public class Livro { ... }

10. Na sequncia crie um teste da Named Query denida no exerccio anterior. www.k19.com.br 54

JPQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class TesteParametros { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); Query query = manager.createNamedQuery("Livro.findByPrecoMinimo"); query.setParameter("preco", 20.0); List<Livro> livros = query.getResultList(); for (Livro livro : livros) { System.out.println("Nome: " + livro.getNome()); System.out.println("Preo: " + livro.getPreco()); } manager.close(); factory.close(); } }

4.5
4.5.1

Tipos de Resultado
Lista de Entidades

Uma consulta em JPQL pode devolver uma lista com os objetos de uma entidade que so compatveis com os ltros da pesquisa. Por exemplo suponha a seguinte consulta:
1 String query = "SELECT p FROM Pessoa p";

O resultado dessa pesquisa uma lista com todas as instncias da entidade P ESSOA que foram persistidas. Esse resultado pode ser obtido atravs do mtodo getResultList().
1 2 3 String query = "SELECT p FROM Pessoa p"; Query query = manager.createQuery(query); List<Pessoa> pessoas = query.getResultList();

Nesse caso, os objetos da listagem devolvida pela consulta esto no estado managed, ou seja, alteraes realizadas no contedo desses objetos sincronizado com o banco de dados de acordo com as regras de sincronizao.

4.5.2
1 2 3

Typed Query

String query = "SELECT p FROM Pessoa p"; Query query = manager.createQuery(query); List<Pessoa> pessoas = query.getResultList();

O compilador da linguagem Java no verica a compatibilidade entre a varivel e o resultado da consulta. Na consulta acima, o compilador no sabe se o mtodo GET R ESULT L IST () devolver de fato uma lista de pessoas pois ele no processa a string que dene a consulta. Sem 55 K19 Treinamentos

JPQL ajuda do compilador h mais chances de erros de execuo. Por exemplo, a consulta abaixo poderia causar problemas.
1 2 3 String query = "SELECT p FROM Pessoa p"; Query query = manager.createQuery(query); List<Departamento> departamentos = query.getResultList();

Para diminuir a chance de erro, podemos utilizar as Typed Queries. Com elas o compilador continua no vericando a string da consulta mas passa a assumir o tipo de resultado e verica todo o cdigo aps a criao da consulta.
1 2 3 String query = "SELECT p FROM Pessoa p"; TypedQuery<Pessoa> query = manager.createQuery(query, Pessoa.class); List<Pessoa> pessoas = query.getResultList();

4.5.3

Lista de Objetos Comuns

A consulta acima devolve uma lista de pessoas. Dessa forma, teramos acesso a todos os dados das pessoas dessa listagem. Contudo, muitas vezes, no desejamos todas as informaes. Por exemplo, se a nossa aplicao precisa apresentar uma lista dos nomes das pessoas cadastradas no necessrio recuperar nada alm dos nomes. Quando denimos as consultas, podemos determinar o que elas devem trazer de fato do banco de dados. Por exemplo, a consulta abaixo recupera apenas os nomes das pessoas.
1 2 3 String query = "SELECT p.nome FROM Pessoa p"; TypedQuery<String> query = manager.createQuery(query, String.class); List<String> nomes = query.getResultList();

4.5.4

Valores nicos

Suponha que desejamos saber quantas pessoas possuem mais do que 18 anos. Nesse caso, no necessrio trazer mais do que um nmero do banco de dados. Em outras palavras, o resultado dessa consulta no deve ser uma lista e sim um valor numrico. Para isso podemos aplicar as funes de agregao: AVG COUNT MAX MIN SUM Calcula a mdia de um conjunto de nmeros Contabiliza o nmero de resultados Recupera o maior elemento um conjunto de nmeros Recupera o menor elemento um conjunto de nmeros Calcula a soma de um conjunto de nmeros

A consulta abaixo devolve a quantidade de pessoas persistidas. Observe que utilizado o mtodo getSingleResult() ao invs do getResultList() pois o resultado no uma lista. www.k19.com.br 56

JPQL
1 2 3 String query = "SELECT COUNT(p) FROM Pessoa p"; TypedQuery<Long> query = manager.createQuery(query, Long.class); Long count = query.getSingleResult();

A consulta abaixo devolve a maior idade entre as pessoas persistidas.


1 2 3 String query = "SELECT MAX(p.idade) FROM Pessoa p"; TypedQuery<Integer> query = manager.createQuery(query, Integer.class); Integer maiorIdade = query.getSingleResult();

4.5.5

Resultados Especiais

Algumas consultas possuem resultados complexos. Por exemplo, suponha que desejamos obter uma listagem com os nomes dos funcionrios e o nome do departamento que o funcionrio trabalha.
1 "SELECT f.nome, f.departamento.nome FROM Funcionario f";

Nesse caso, o resultado ser uma lista de array de Object. Para manipular essa lista devemos lidar com o posicionamento dos dados nos arrays.
1 2 3 4 5 6 7 8 String query = "SELECT f.nome, f.departamento.nome FROM Funcionario f"; Query query = manager.createQuery(query); List<Object[]> lista = query.getResultList(); for(Object[] tupla : lista) { System.out.println("Funcionrio: " + tupla[0]); System.out.println("Departamento: " + tupla[1]); }

4.5.6

Operador NEW

Para contornar a diculdade de lidar com o posicionamento dos dados nos arrays, podemos criar uma classe para modelar o resultado da nossa consulta e aplicar o operador NEW no cdigo JPQL.
1 2 3 4 5 6 7 8 9 10 11 12 13 package resultado; class FuncionarioDepartamento { private String funcionarioNome; private String departamentoNome; public FuncionarioDepartamento(String funcionarioNome, String departamentoNome) { this.funcionarioNome = funcionarioNome; this.departamentoNome = departamentoNome; } // GETTERS AND SETTERS }

57

K19 Treinamentos

JPQL
1 2 3 4 5 6 7 8 9 10 11 String query = "SELECT NEW resultado.FuncionarioDepartamento(f.nome, f.departamento.nome) FROM Funcionario f"; Query<FuncionarioDepartamento> query = manager.createQuery(query); List<FuncionarioDepartamento> resultados = query.getResultList(); for(FuncionarioDepartamento resultado : resultados) { System.out.println("Funcionrio: " + resultado.getFuncionarioNome()); System.out.println("Departamento: " + resultado.getDepartamentoNome()); }

4.6

Exerccios

11. Teste o recurso de Typed Query utilizando a Named Query AUTOR . FINDA LL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class TesteTypedQuery { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); TypedQuery<Autor> query = manager.createNamedQuery("Autor.findAll", Autor.class ); List<Autor> autores = query.getResultList(); for (Autor autor : autores) { System.out.println("Autor: " + autor.getNome()); } manager.close(); factory.close(); } }

Observe que no h mais warnings 12. Crie um teste para recuperar somente os nomes dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class TesteConsultaObjetosComuns { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); TypedQuery<String> query = manager.createQuery("select livro.nome from Livro livro", String.class); List<String> nomes = query.getResultList(); for (String nome : nomes) { System.out.println(nome); } manager.close(); factory.close(); } }

www.k19.com.br

58

JPQL 13. Crie um teste para recuperar o valor da mdia dos preos dos livros. Adicione a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

public class TesteConsultaLivroPrecoMedio { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); TypedQuery<Double> query = manager.createQuery("select avg(livro.preco) from Livro livro", Double.class); Double precoMedio = query.getSingleResult(); System.out.println("Preo mdio: " + precoMedio); manager.close(); factory.close(); } }

14. Crie mais duas entidades no pacote modelo.

1 2 3 4 5 6 7 8 9 10

@Entity public class Departamento { @Id @GeneratedValue private Long id; private String nome; // GETTERS AND SETTERS }

1 2 3 4 5 6 7 8 9 10 11 12 13

@Entity public class Funcionario { @Id @GeneratedValue private Long id; private String nome; @ManyToOne private Departamento departamento; // GETTERS AND SETTERS }

15. Adicione alguns funcionrios e departamentos. 59 K19 Treinamentos

JPQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class AdicionaFuncionarioDepartamento { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Departamento d = new Departamento(); d.setNome("Treinamentos"); Funcionario f = new Funcionario(); f.setNome("Rafael Cosentino"); f.setDepartamento(d); manager.persist(f); manager.persist(d); manager.getTransaction().commit(); manager.close(); factory.close(); } }

16. Crie um teste para recuperar os nomes dos funcionrios e os nomes dos seus respectivos departamentos. Adicione a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

public class TesteBuscaFuncionarioDepartamento { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Query query = manager .createQuery("select f.nome, f.departamento.nome from Funcionario f"); List<Object[]> lista = query.getResultList(); for (Object[] tupla : lista) { System.out.println("Funcionrio: " + tupla[0]); System.out.println("Departamento: " + tupla[1]); } manager.close(); factory.close(); } }

17. Crie no pacote modelo uma classe para melhorar a manipulao da consulta dos nomes dos funcionrios e nomes dos seus respectivos departamentos. www.k19.com.br 60

JPQL
1 2 3 4 5 6 7 8 9 10 11 public class FuncionarioDepartamento { private String funcionario; private String departamento; public FuncionarioDepartamento(String funcionario, String departamento) { this.funcionario = funcionario; this.departamento = departamento; } // GETTERS AND SETTERS }

18. Altere a classe TesteBuscaFuncionarioDepartamento para que ela utilize o operador NEW da JPQL.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

public class TesteBuscaFuncionarioDepartamento { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Query query = manager .createQuery("select new modelo.FuncionarioDepartamento(f.nome, f. departamento.nome) from Funcionario f"); List<FuncionarioDepartamento> lista = query.getResultList(); for (FuncionarioDepartamento fd : lista) { System.out.println("Funcionrio: " + fd.getFuncionario()); System.out.println("Departamento: " + fd.getDepartamento()); } manager.close(); factory.close(); } }

4.7

Paginao

Supondo que exista uma grande quantidade de livros cadastrados no banco de dados, buscar todos os livros sem nenhum ltro vai sobrecarregar a memria utilizada pela aplicao. Nesses casos, podemos aplicar o conceito de paginao para obter os livros aos poucos. A paginao realizada atravs dos mtodos setFirstResult() e setMaxResults().
1 2 3 4 TypedQuery<Livro> query = manager.createQuery("select livro from Livro livro", Livro. class); query.setFirstResult(10); query.setMaxResults(20); List<Livro> livros = query.getResultList();

61

K19 Treinamentos

JPQL

4.8

Exerccios

19. Teste o recurso de paginao das consultas. Adicione a seguinte classe no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TesteBuscaPaginada { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_jpql"); EntityManager manager = factory.createEntityManager(); TypedQuery<Livro> query = manager.createQuery("select livro from Livro livro", Livro.class); query.setFirstResult(2); query.setMaxResults(3); List<Livro> livros = query.getResultList(); for (Livro livro : livros) { System.out.println("Livro: " + livro.getNome()); } manager.close(); factory.close(); } }

4.9

Operadores

As consultas em JPQL utilizam alguns tipos de operadores.

4.9.1

Condicionais

Menor(<)
1 String query = "SELECT p FROM Pessoa p WHERE p.idade < :idade";

Maior(>)
1 String query = "SELECT p FROM Pessoa p WHERE p.idade > :idade";

Menor Igual(<=)
1 String query = "SELECT p FROM Pessoa p WHERE p.idade <= :idade";

Maior Igual(>=) www.k19.com.br 62

JPQL
1 String query = "SELECT p FROM Pessoa p WHERE p.idade >= :idade";

Igual(=)
1 String query = "SELECT p FROM Pessoa p WHERE p.idade = :idade";

Diferente(<>)
1 String query = "SELECT p FROM Pessoa p WHERE p.idade <> :idade";

IS NULL
1 String query = "SELECT p FROM Pessoa p WHERE p.nome IS NULL";

IS NOT NULL
1 String query = "SELECT p FROM Pessoa p WHERE p.nome IS NOT NULL";

BETWEEN
1 String query = "SELECT p FROM Pessoa p WHERE p.idade BETWEEN :minimo AND :maximo";

NOT BETWEEN
1 String query = "SELECT p FROM Pessoa p WHERE p.idade NOT BETWEEN :minimo AND :maximo";

AND
1 String query = "SELECT p FROM Pessoa p WHERE p.nome IS NOT NULL AND p.idade >= :idade";

OR
1 String query = "SELECT p FROM Pessoa p WHERE p.nome IS NOT NULL OR p.idade >= :idade";

63

K19 Treinamentos

JPQL NOT
1 String query = "SELECT p FROM Pessoa p WHERE NOT (p.idade >= :idade)";

MEMBER OF
1 String query = "SELECT f FROM Funcionario f WHERE f MEMBER OF f.empresa.diretoria";

NOT MEMBER OF
1 String query = "SELECT f FROM Funcionario f WHERE f NOT MEMBER OF f.empresa.diretoria";

IS EMPTY
1 String query = "SELECT a FROM Autor a WHERE a.livros IS EMPTY";

IS NOT EMPTY
1 String query = "SELECT a FROM Autor a WHERE a.livros IS NOT EMPTY";

EXISTS
1 String query = "SELECT d FROM Departamento d WHERE EXISTS (SELECT f FROM FUNCIONARIO f WHERE f.departamento = d)";

NOT EXISTS
1 String query = "SELECT d FROM Departamento d WHERE NOT EXISTS (SELECT f FROM FUNCIONARIO f WHERE f.departamento = d)";

LIKE
1 String query = "SELECT a FROM Autor a WHERE a.nome LIKE Patrick%";

www.k19.com.br

64

JPQL NOT LIKE


1 String query = "SELECT a FROM Autor a WHERE a.nome NOT LIKE Patrick%";

IN
1 String query = "SELECT a FROM Autor a WHERE a.nome IN (Patrick Cullen, Fraser Seitel )";

NOT IN
1 String query = "SELECT a FROM Autor a WHERE a.nome NOT IN (Patrick Cullen, Fraser Seitel)";

4.9.2

Escalares

ALL
1 String query = "SELECT livro FROM Livro livro WHERE livro.preco >= ALL(SELECT livro. preco FROM Livro livro)";

ANY
1 String query = "SELECT livro FROM Livro livro WHERE livro.preco >= ANY(SELECT livro. preco FROM Livro livro)";

SOME
1 String query = "SELECT livro FROM Livro livro WHERE livro.preco >= ANY(SELECT livro. preco FROM Livro livro)";

4.9.3

Agregadores

AVG
1 String query = "SELECT AVG(livro.preco) FROM Livro livro";

65

K19 Treinamentos

JPQL SUM
1 String query = "SELECT SUM(livro.preco) FROM Livro livro";

MIN
1 String query = "SELECT MIN(livro.preco) FROM Livro livro";

MAX
1 String query = "SELECT MAX(livro.preco) FROM Livro livro";

COUNT
1 String query = "SELECT COUNT(livro) FROM Livro livro";

4.9.4

Funes

ABS: Calcula o valor absoluto de um nmero. CONCAT: Concatena strings. CURRENT_DATE: Recupera a data atual. CURRENT_TIME: Recupera o horrio atual. CURRENT_TIMESTAMP: Recupera a data e o horrio atuais. LENGTH: Calcula o nmero de caracteres de uma string. LOCATE: Localiza uma string dentro de outra. LOWER: Deixa as letras de uma string minsculas. MOD: Calcula o resto da diviso entre dois nmeros. SIZE: Calcula o nmero de elementos de uma coleo. SQRT: Calcula a raiz quadrada de um nmero. SUBSTRING: Recupera um trecho de uma string. UPPER: Deixa as letras de uma string maisculas. TRIM: Elimina espaos do incio e m de uma string. www.k19.com.br 66

JPQL

4.9.5

ORDER BY

Podemos ordenar o resultado de uma consulta atravs do operador ORDER BY.


1 String query = "SELECT livro FROM Livro livro ORDER BY livro.preco ASC";

4.10

Exemplos

1. Suponha que seja necessrio selecionar os livros mais baratos. Em outras palavras, devemos selecionar os livros tais quais no exista nenhum outro livro com preo menor.
1 2 3 4 5 6 7 SELECT livro1 FROM Livro livro1 WHERE NOT EXISTS ( SELECT livro2 FROM Livro livro2 WHERE livro1.preco > livro2.preco )

2. Suponha que seja necessrio selecionar os livros mais baratos de um determinado autor.
1 2 3 4 5 6 7 8 9 10 11 SELECT livro1 FROM Livro livro1, Autor autor1 WHERE autor1.nome = :nome and livro1 MEMBER OF autor1.livros and NOT EXISTS ( SELECT livro2 FROM Livro livro2, Autor autor2 WHERE autor2 = autor1 and livro2 MEMBER OF autor2.livros and livro1.preco > livro2.preco )

3. Suponha que seja necessrio listar os livros em ordem decrescente em relao aos preos.
1 SELECT livro FROM Livro livro ORDER BY livro.preco DESC

4. Suponha que seja necessrio selecionar os autores com mais livros.


1 2 3 4 5 6 7 SELECT autor1 FROM Autor autor1 WHERE NOT EXISTS ( SELECT autor2 FROM Autor autor2 WHERE SIZE(autor2.livros) > SIZE(autor1.livros) )

67

K19 Treinamentos

JPQL

4.11

Referncias

Para conhecer mais sobre a sintaxe do JPQL consulte essas referncias: http://openjpa.apache.org/builds/latest/docs/manual/jpa_overview_ query.html http://openjpa.apache.org/builds/latest/docs/manual/jpa_langref. html

www.k19.com.br

68

Captulo 5 Criteria
O primeiro mecanismo denido pela especicao JPA 2 para realizar consultas orientadas a objetos utiliza a linguagem JPQL. O segundo mecanismo utiliza um conjunto de classes e interfaces e funciona basicamente como uma biblioteca. O nome dessa segunda abordagem Criteria API.

5.1

Necessidade

A primeira questo a ser discutida nesse momento a necessidade de dois mecanismos de denio de consultas. Um mecanismo s no seria suciente? Teoricamente, qualquer consulta denida com JPQL pode ser denida com Criteria API e vice versa. Contudo, algumas consultas so mais facilmente denidas em JPQL enquanto outras mais facilmente denidas em Criteria API. As consultas que no dependem de informaes externas (ex. buscar todos os livros cadastrados no banco de dados sem nenhum ltro) so mais facilmente denidas em JPQL. As consultas que dependem de informaes externas xas (ex. buscar todos os livros cadastrados no banco de dados que possuam preo maior do que um valor denido pelos usurios) tambm so mais facilmente criadas em JPQL utilizando os parmetros de consulta. Agora, as consultas que dependem de informaes externas no xas so mais facilmente denidas em Criteria API. Por exemplo, suponha uma busca avanada de livros na qual h muitos campos opcionais. Essa consulta depende de informaes externas no xas j que nem todo campo far parte da consulta todas as vezes que ela for executada.

5.2

Estrutura Geral

As duas interfaces principais da Criteria API so: CriteriaBuilder e CriteriaQuery. As consultas em Criteria API so construdas por um Criteria Builder que obtido atravs de um Entity Manager.
1 CriteriaBuilder cb = manager.getCriteriaBuilder();

A denio de uma consulta em Criteria API comea na chamada do mtodo 69

CREATE -

Criteria Q UERY () de um Criteria Builder. O parmetro desse mtodo indica o tipo esperado do resultado da consulta.
1 2 CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Autor> c = cb.createQuery(Autor.class);

Para denir o espao de dados que a consulta deve considerar, devemos utilizar o mtodo from() da Criteria Query. Este mtodo devolve uma raiz do espao de dados considerado pela pesquisa.
1 2 3 4 CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Autor> c = cb.createQuery(Autor.class); // DEFININDO O ESPAO DE DADOS DA CONSULTA Root<Autor> a = c.from(Autor.class);

Para denir o que queremos selecionar do espao de dados da consulta, devemos utilizar o mtodo select() da Criteria Query.
1 2 3 4 5 6 CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Autor> c = cb.createQuery(Autor.class); // DEFININDO O ESPAO DE DADOS DA CONSULTA Root<Autor> a = c.from(Autor.class); // SELECIONANDO UMA RAIZ DO ESPAO DE DADOS c.select(a);

Com a consulta em Criteria API denida, devemos invocar um Entity Manager para poder execut-la da seguinte forma.
1 2 TypedQuery<Autor> query = manager.createQuery(c); List<Autor> autores = query.getResultList();

5.3

Exerccios

1. Crie um projeto no eclipse chamado Criteria. Copie a pasta lib do projeto EntityManager para o projeto Criteria. Depois selecione todos os jars e os adicione no classpath. 2. Abra o MySQL Query Browser e apague a base de dados K21_criteria se existir. Depois crie a base de dados K21_criteria. 3. Copie a pasta META-INF do projeto EntityManager para dentro da pasta src do projeto Criteria. Altere o arquivo persistence.xml do projeto Criteria, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car: www.k19.com.br 70

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_criteria" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver " /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="root" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_criteria" /> </properties> </persistence-unit> </persistence>

4. Crie um pacote chamado modelo no projeto Criteria e adicione as seguintes classes:


1 2 3 4 5 6 7 8 9 10 11 12 13 @Entity public class Autor { @Id @GeneratedValue private Long id; private String nome; @ManyToMany private Collection<Livro> livros = new ArrayList<Livro>(); // GETTERS E SETTERS }

1 2 3 4 5 6 7 8 9 10 11 12

@Entity public class Livro { @Id @GeneratedValue private Long id; private String nome; private Double preco; // GETTERS E SETTERS }

5. Carregue o banco de dados com as informaes de alguns livros e autores. Adicione a seguinte classe em um novo pacote chamado testes. Voc pode copiar a classe PopulaBanco criada no projeto JPQL e alterar a unidade de persistncia. 71 K19 Treinamentos

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 public class PopulaBanco { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Livro livro1 = new Livro(); livro1.setNome("The Battle for Your Mind"); livro1.setPreco(20.6); manager.persist(livro1); Livro livro2 = new Livro(); livro2.setNome("Differentiate or Die"); livro2.setPreco(15.8); manager.persist(livro2); Livro livro3 = new Livro(); livro3.setNome("How to Transform Your Ideas"); livro3.setPreco(32.7); manager.persist(livro3); Livro livro4 = new Livro(); livro4.setNome("Digital Fortress"); livro4.setPreco(12.9); manager.persist(livro4); Livro livro5 = new Livro(); livro5.setNome("Marketing in an Era of Competition, Change and Crisis"); livro5.setPreco(26.8); manager.persist(livro5); Autor autor1 = new Autor(); autor1.setNome("Patrick Cullen"); autor1.getLivros().add(livro2); autor1.getLivros().add(livro4); manager.persist(autor1); Autor autor2 = new Autor(); autor2.setNome("Fraser Seitel"); autor2.getLivros().add(livro3); manager.persist(autor2); Autor autor3 = new Autor(); autor3.setNome("Al Ries"); autor3.getLivros().add(livro1); manager.persist(autor3); Autor autor4 = new Autor(); autor4.setNome("Jack Trout"); autor4.getLivros().add(livro1); autor4.getLivros().add(livro2); autor4.getLivros().add(livro5); manager.persist(autor4); Autor autor5 = new Autor(); autor5.setNome("Steve Rivkin"); autor5.getLivros().add(livro2); autor5.getLivros().add(livro3); autor5.getLivros().add(livro5); manager.persist(autor5); manager.getTransaction().commit(); manager.close(); factory.close(); } }

www.k19.com.br

72

Criteria 6. Teste a Criteria API criando uma consulta para recuperar todos os livros cadastrados no banco de dados. Crie a seguinte classe no pacote testes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class TesteCriteria { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager();

CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> l = c.from(Livro.class); c.select(l); TypedQuery<Livro> query = manager.createQuery(c); List<Livro> livros = query.getResultList(); for (Livro livro : livros) { System.out.println(livro.getNome()); } } }

7. (Opcional) Crie uma consulta utilizando a Criteria API para recuperar todos os autores.

5.4
5.4.1

Tipos de Resultados
Lista de Entidades

O resultado de uma consulta em Criteria API pode ser uma lista com os objetos de uma entidade que so compatveis com os ltros da pesquisa.
1 2 3 CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro = c.from(Livro.class); c.select(livro);

O resultado da consulta acima uma lista com todos os objetos da classe L IVRO.

5.4.2

Lista de Objetos Comuns

Muitas vezes, no queremos selecionar todas as informaes dos objetos pesquisados. Por exemplo, suponha que seja necessrio gerar uma lista com os nomes dos livros cadastrados no banco de dados. Atravs do mtodo SELECT () podemos denir o que deve ser recuperado do banco de dados.
1 2 3 CriteriaQuery<String> c = cb.createQuery(String.class); Root<Livro> livro = c.from(Livro.class); c.select(livro.<String>get("nome"));

A consulta acima recupera apenas os nomes dos livros. O resultado dessa pesquisa uma lista de strings. 73 K19 Treinamentos

Criteria

5.4.3

Valores nicos

Algumas consultas possuem como resultado valores nicos. Por exemplo, suponha que queremos obter a mdia dos preos dos livros cadastrados no banco de dados ou a quantidade de livros de uma determinada editora. Nesse tipo de consulta, devemos apenas trazer do banco de dados um valor nico calculado no prprio banco.
1 2 3 CriteriaQuery<Double> c = cb.createQuery(Double.class); Root<Livro> l = c.from(Livro.class); c.select(cb.avg(l.<Double>get("preco")));

A consulta acima devolve a mdia dos preos dos livros cadastrados no banco de dados. Nessa consulta, foi utilizada uma funo de agregao. Veja a lista dessas funes: avg() count() max() e greatest() min() e least() sum(), sumAsLong() e sumAsDouble() Calcula a mdia de um conjunto de nmeros Contabiliza o nmero de resultados Recupera o maior elemento um conjunto de nmeros Recupera o menor elemento um conjunto de nmeros Calcula a soma de um conjunto de nmeros

5.4.4

Resultados Especias

Podemos selecionar mltiplos atributos de uma entidade em uma consulta em Criteria API. Por exemplo, podemos montar uma listagem com os nomes e preos dos livros cadastrados no banco de dados. Para selecionar mltiplos atributos, devemos utilizar o mtodo MULTISE LECT ().
1 2 3 CriteriaQuery<Object[]> c = cb.createQuery(Object[].class); Root<Livro> l = c.from(Livro.class); c.multiselect(l.<String>get("nome"), l.<Double>get("preco"));

O resultado da consulta acima uma lista de array de Object. Para manipular esse resultado, temos que utilizar a posio dos dados dos arrays da lista.
1 2 3 4 5 6 7 TypedQuery<Object[]> query = manager.createQuery(c); List<Object[]> resultado = query.getResultList(); for (Object[] registro : resultado) { System.out.println("Livro: " + registro[0]); System.out.println("Preo: " + registro[1]); }

Tambm podemos utilizar a interface T UPLE para no trabalhar com posicionamento de dados em arrays. Nessa abordagem, devemos aplicar "apelidos"para os itens selecionados atravs do mtodo ALIAS (). www.k19.com.br 74

Criteria
1 2 3 4 5 6 7 8 9 10 11 CriteriaQuery<Tuple> c = cb.createQuery(Tuple.class); Root<Livro> l = c.from(Livro.class); c.multiselect(l.<String>get("nome").alias("livro.nome"), l.<Double>get("preco").alias(" livro.preco")); TypedQuery<Tuple> query = manager.createQuery(c); List<Tuple> resultado = query.getResultList(); for (Tuple registro : resultado) { System.out.println("Livro: " + registro.get("livro.nome")); System.out.println("Preo: " + registro.get("livro.preco")); }

5.5

Exerccios

8. Recupere uma listagem com os nomes dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

public class ListaNomesDosLivros { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<String> c = cb.createQuery(String.class); Root<Livro> livro = c.from(Livro.class); c.select(livro.<String>get("nome")); TypedQuery<String> query = manager.createQuery(c); List<String> nomes = query.getResultList(); for (String nome : nomes) { System.out.println("Livro: " + nome); } manager.close(); factory.close(); } }

9. Recupere a mdia dos valores dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote testes. 75 K19 Treinamentos

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CalculaMediaDosPrecosDosLivros { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Double> c = cb.createQuery(Double.class); Root<Livro> l = c.from(Livro.class); c.select(cb.avg(l.<Double>get("preco"))); TypedQuery<Double> query = manager.createQuery(c); Double media = query.getSingleResult(); System.out.println("Mdia: " + media); manager.close(); factory.close(); } }

10. Recupere os nomes e os preos dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

public class ConsultaNomePrecoDosLivros { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Object[]> c = cb.createQuery(Object[].class); Root<Livro> l = c.from(Livro.class); c.multiselect(l.<String>get("nome"), l.<Double>get("preco")); TypedQuery<Object[]> query = manager.createQuery(c); List<Object[]> resultado = query.getResultList(); for (Object[] registro : resultado) { System.out.println("Livro: " + registro[0]); System.out.println("Preo: " + registro[1]); } manager.close(); factory.close(); } }

11. Altere a classe do exerccio anterior para que ela utilize a interface Tuple. www.k19.com.br 76

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class ConsultaNomePrecoDosLivros { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Tuple> c = cb.createQuery(Tuple.class); Root<Livro> l = c.from(Livro.class); c.multiselect(l.<String>get("nome").alias("livro.nome"), l.<Double>get("preco") .alias("livro.preco")); TypedQuery<Tuple> query = manager.createQuery(c); List<Tuple> resultado = query.getResultList(); for (Tuple registro : resultado) { System.out.println("Livro: " + registro.get("livro.nome")); System.out.println("Preo: " + registro.get("livro.preco")); } manager.close(); factory.close(); } }

5.6

Filtros e Predicados

Podemos denir ltros para as consultas atravs da criao de Predicates e do mtodo where() de uma Criteria Query. Os predicates so condies que devem ser satisfeitas para que uma informao seja adicionada no resultado de uma consulta. E eles so criados por um Criteria Builder.
1 2 3 4 5 6 7 8 9 CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Autor> c = cb.createQuery(Autor.class); Root<Autor> a = c.from(Autor.class); c.select(a); // CRIANDO UM PREDICATE Predicate predicate = cb.equal(a.get("nome"), "Patrick Cullen"); // ASSOCIANDO O PREDICATE A CONSULTA c.where(predicate);

5.7

Exerccios

12. Teste a Criteria API criando uma consulta para recuperar todos os livros cadastrados no banco de dados. Crie a seguinte classe no pacote testes. 77 K19 Treinamentos

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TestePredicate { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_criteria"); EntityManager manager = factory.createEntityManager(); CriteriaBuilder cb = manager.getCriteriaBuilder(); CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> l = c.from(Livro.class); c.select(l); Predicate predicate = cb.equal(l.get("nome"), "The Battle for Your Mind"); c.where(predicate); TypedQuery<Livro> query = manager.createQuery(c); List<Livro> livros = query.getResultList(); for (Livro livro : livros) { System.out.println(livro.getId()); System.out.println(livro.getNome()); System.out.println(livro.getPreco()); } } }

5.8

Lista de Predicados

equal()
1 cb.equal(livro.get("nome"), "The Battle for Your Mind");

and()
1 cb.and(cb.equal(livro.get("nome"), "Noites"), cb.equal(livro.get("editora"), "Saraiva") );

or()
1 cb.or(cb.equal(livro.get("nome"), "Noites"), cb.equal(livro.get("editora"), "Saraiva")) ;

notEqual()
1 cb.notEqual(livro.get("nome"), "The Battle for Your Mind");

not() www.k19.com.br 78

Criteria
1 cb.not(cb.equal(livro.get("nome"), "The Battle for Your Mind"));

greaterThan(), gt()
1 cb.gt(livro.<Double>get("preco"), 20.0);

ou
1 cb.greaterThan(livro.<Double>get("preco"), 20.0);

greaterThanOrEqualTo(), ge()
1 cb.ge(livro.<Double>get("preco"), 20.0);

ou
1 cb.greaterThanOrEqualTo(livro.<Double>get("preco"), 20.0);

lessThan(), lt()
1 cb.lt(livro.<Double>get("preco"), 20.0);

ou
1 cb.lessThan(livro.<Double>get("preco"), 20.0);

lessThanOrEqualTo(), le()
1 cb.le(livro.<Double>get("preco"), 20.0);

ou
1 cb.lessThanOrEqualTo(livro.<Double>get("preco"), 20.0);

79

K19 Treinamentos

Criteria between()
1 cb.between(livro.<Double>get("preco"), 20.0, 30.0);

isNull()
1 cb.isNull(livro.get("nome"));

isNotNull()
1 cb.isNotNull(livro.get("nome"));

isEmpty()
1 cb.isEmpty(autor.<Collection<Livro>>get("livros"));

isNotEmpty()
1 cb.isNotEmpty(autor.<Collection<Livro>>get("livros"));

isMember()
1 cb.isMember(livro, livro.<Editora>get("editora").<Collection<Livro>>get("maisVendidos") );

isNotMember()
1 cb.isNotMember(livro, livro.<Editora>get("editora").<Collection<Livro>>get(" maisVendidos"));

like()
1 cb.like(livro.<String>get("nome"), "%Battle%");

www.k19.com.br

80

Criteria notLike()
1 cb.notLike(livro.<String>get("nome"), "%Battle%");

in()
1 cb.in(livro.<String>get("editora")).value("Saraiva").value("Moderna");

ou
1 livro.<String>get("editora").in("Saraiva","Moderna");

5.9

Funes

abs()
1 cb.abs(livro.<Double>get("preco"));

concat()
1 cb.concat(livro1.<String>get("nome"), livro2.<String>get("nome"));

currentDate()
1 cb.currentDate();

currentTime()
1 cb.currentTime();

currentTimestamp()
1 cb.currentTimestamp();

81

K19 Treinamentos

Criteria length()
1 cb.length(livro.<String>get("nome"));

locate()
1 cb.locate(livro1.<String>get("nome"), livro2.<String>get("nome"));

lower()
1 cb.lower(livro.<String>get("nome"));

mod()
1 cb.mod(autor1.<Integer>get("idade"), autor2.<Integer>get("idade"));

size()
1 cb.size(autor.<Collection<Livro>>get("livros"));

sqrt()
1 cb.sqrt(autor.<Integer>get("idade"));

substring()
1 cb.substring(livro.<String>get("nome"), 3, 5);

upper()
1 cb.upper(livro.<String>get("nome"));

www.k19.com.br

82

Criteria trim()

cb.trim(livro.<String>get("nome"));

5.10

Ordenao

As consultas em Criteria API tambm podem ser ordenadas, basta utilizarmos o mtodo
ORDER B Y ()
1 2 3 4 5 CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro = c.from(Livro.class); c.select(livro); c.orderBy(cb.desc(livro.<Double>get("preco")));

5.11

Subqueries

Algumas consultas necessitam de consultas auxiliares. Por exemplo, para encontrar o livro mais caro cadastrado no banco de dados devemos criar uma consulta auxiliar para poder comparar, dois a dois, os preos dos livros. Uma consulta auxiliar ou uma subquery criada atravs do mtodo SUBQUERY (). No exemplo, abaixo criamos uma consulta e uma subconsulta para encotrar o livro mais caro.
1 2 3 4 5 6 7 8 9 10 11 12 13 CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro1 = c.from(Livro.class); c.select(livro1); Subquery<Livro> subquery = c.subquery(Livro.class); Root<Livro> livro2 = subquery.from(Livro.class); subquery.select(a2); Predicate predicate = cb.greaterThan(livro2.<Double>get("preco"), livro1.<Double>get(" preco")); subquery.where(predicate); Predicate predicate2 = cb.not(cb.exists(subquery)); c.where(predicate2);

5.12

Exemplos

1. Suponha que seja necessrio selecionar os livros mais baratos. Em outras palavras, devemos selecionar os livros tais quais no exista nenhum outro livro com preo menor. 83 K19 Treinamentos

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro1 = c.from(Livro.class); c.select(livro1); Subquery<Livro> subquery = c.subquery(Livro.class); Root<Livro> livro2 = subquery.from(Livro.class); subquery.select(livro2); Predicate gt = cb.gt(livro1.<Double>get("preco"), livro2.<Double>get("preco")); subquery.where(gt); Predicate notExists = cb.not(cb.exists(subquery)); c.where(notExists);

2. Suponha que seja necessrio selecionar os livros mais baratos de um determinado autor.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro1 = c.from(Livro.class); Root<Autor> autor1 = c.from(Autor.class); c.select(livro1); Subquery<Livro> subquery = c.subquery(Livro.class); Root<Livro> livro2 = subquery.from(Livro.class); Root<Autor> autor2 = subquery.from(Autor.class); subquery.select(livro2); Predicate isMember1 = cb.isMember(livro2, autor2.<Collection<Livro>>get("livros")); Predicate equal1 = cb.equal(autor2, autor1); Predicate gt = cb.gt(livro1.<Double>get("preco"), livro2.<Double>get("preco")); Predicate predicate = cb.and(isMember1,equal1,gt); subquery.where(predicate); Predicate notExists = cb.not(cb.exists(subquery)); Predicate equal2 = cb.equal(autor1.<String>get("nome"), "Jack Trout"); Predicate isMember2 = cb.isMember(livro1, autor1.<Collection<Livro>>get("livros")); Predicate predicate2 = cb.and(isMember2,equal2,notExists); c.where(predicate2);

3. Suponha que seja necessrio listar os livros em ordem decrescente em relao aos preos.

1 2 3 4

CriteriaQuery<Livro> c = cb.createQuery(Livro.class); Root<Livro> livro = c.from(Livro.class); c.select(livro); c.orderBy(cb.desc(livro.<Double>get("preco")));

4. Suponha que seja necessrio selecionar os autores com mais livros. www.k19.com.br 84

Criteria
1 2 3 4 5 6 7 8 9 10 11 12 CriteriaQuery<Autor> c = cb.createQuery(Autor.class); Root<Autor> autor1 = c.from(Autor.class); c.select(autor1); Subquery<Autor> subquery = c.subquery(Autor.class); Root<Autor> autor2 = subquery.from(Autor.class); subquery.select(autor2); Predicate gt = cb.gt(cb.size(autor2.<Collection<Livro>>get("livros")), cb.size(autor1.< Collection<Livro>>get("livros"))); subquery.where(gt); Predicate notExists = cb.not(cb.exists(subquery)); c.where(notExists);

85

K19 Treinamentos

Criteria

www.k19.com.br

86

Captulo 6 Tpicos Avanados


6.1 Operaes em Lote - Bulk Operations

Para atualizar ou remover registros das tabelas do banco de dados, a abordagem mais comum realizar uma consulta trazendo para a memria os objetos referentes aos registros que devem ser modicados ou removidos.
1 2 Pessoa p = manager.find(Pessoa.class, 1L); p.setNome("Rafael Cosentino");

1 2

Pessoa p = manager.find(Pessoa.class, 1L); manager.remove(p);

Em alguns casos essa abordagem no a mais eciente. Por exemplo, suponha que uma aplicao que controla os produtos de uma loja virtual necessite atualizar os preos de todos os produtos com uma taxa xa.
1 2 3 4 5 6 TypedQuery<Produto> query = manager.createNamedQuery("Produto.findAll"); List<Produto> produtos = query.getResultList(); for(Produto p : produtos) { double preco = p.getPreco(); p.setPreco(preco * 1.1); // 10% de aumento }

Todos os produtos seriam carregados na aplicao sobrecarregando a rede pois uma grande quantidade de dados seria transferida do banco de dados para a aplicao e a memria pois muitos objetos seriam criados pelo provedor JPA. A abordagem mais eciente nesse caso realizar uma operao em lote (bulk operation). Uma operao em lote executada no banco de dados sem transferir os dados dos registros para a memria da aplicao.
1 2 Query query = manager.createQuery("UPDATE Produto p SET p.preco = p.preco * 1.1"); query.executeUpdate();

87

Tpicos Avanados A mesma estratgia pode ser adotada quando diversos registros devem ser removidos. No necessrio carregar os objetos na memria para remov-los, basta realizar uma operao em lote.
1 2 Query query = manager.createQuery("DELETE Produto p WHERE p.preco < 50"); query.executeUpdate();

6.2

Exerccios

1. Crie um projeto no eclipse chamado TopicosAvancados. Copie a pasta lib do projeto EntityManager para o projeto TopicosAvancados. Depois selecione todos os jars e os adicione no classpath. 2. Abra o MySQL Query Browser e apague a base de dados K21_topicos_avancados se existir. Depois crie a base de dados K21_topicos_avancados. 3. Copie a pasta META-INF do projeto EntityManager para dentro da pasta src do projeto TopicosAvancados. Altere o arquivo persistence.xml do projeto TopicosAvancados, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8"?> <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_1_0.xsd" version="1.0"> <persistence-unit name="K21_topicos_avancados" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect. MySQL5InnoDBDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver " /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="root" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:// localhost:3306/K21_topicos_avancados" /> </properties> </persistence-unit> </persistence>

4. Crie um pacote chamado modelo no projeto TopicosAvancados e adicione a seguinte classe: www.k19.com.br 88

Tpicos Avanados
1 2 3 4 5 6 7 8 9 10 11 12 @Entity public class Produto { @Id @GeneratedValue private Long id; private String nome; private Double preco; // GETTERS E SETTERS }

5. Adicione alguns produtos no banco de dados. Crie a seguinte classe em um pacote chamado testes no projeto TopicosAvancados.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

public class PopulaBanco { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); for (int i = 0; i < 100; i++) { Produto p = new Produto(); p.setNome("produto " + i); p.setPreco(i * 10.0); manager.persist(p); } manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e verique a tabela produto na base de dados K21_topicos_avancados

6. Faa uma operao em lote para atualizar o preo de todos os produtos de acordo com uma taxa xa. 89 K19 Treinamentos

Tpicos Avanados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class AumentaPreco { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Query query = manager .createQuery("UPDATE Produto p SET p.preco = p.preco * 1.1"); query.executeUpdate(); manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e verique a tabela produto na base de dados K21_topicos_avancados Observe tambm o console do eclipse. Nenhum select realizado 7. Faa uma operao em lote para remover todos os produtos com preo menor do que um valor xo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class RemoveProdutos { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Query query = manager .createQuery("DELETE Produto p WHERE p.preco < 50"); query.executeUpdate(); manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e verique a tabela produto na base de dados K21_topicos_avancados Observe tambm o console do eclipse. Nenhum select realizado

6.3

Concorrncia

Quando dois Entity Managers manipulam objetos da mesma entidade e com o mesmo identicador, um resultado incorreto pode ser obtido. Por exemplo, suponha que os seguintes trechos de cdigo sejam executados em paralelo. www.k19.com.br 90

Tpicos Avanados
1 2 3 4 5 6 7 manager1.getTransaction().begin(); Conta x = manager1.find(Conta.class, 1L); x.setSaldo(x.getSaldo() + 500); manager1.getTransaction().commit();

1 2 3 4 5 6 7

manager2.getTransaction().begin(); Conta y = manager2.find(Conta.class, 1L); y.setSaldo(y.getSaldo() - 500); manager2.getTransaction().commit();

O primeiro trecho acrescenta 500 reias no saldo da conta com identicador 1. O segundo trecho retira 500 reais da mesma conta. Dessa forma, o saldo dessa conta deve possuir o mesmo valor antes e depois desses dois trechos de cdigo executarem. Contudo, dependendo da ordem na qual as linhas dos dois trechos so executadas o resultado pode ser outro. Por exemplo, suponha que o valor inicial do saldo da conta com identicador 1 seja 2000 reais e as linhas dos dois trechos so executadas na seguinte ordem:
1 2 3 4 5 6 7 8 9 10 11 12 13 manager1.getTransaction().begin(); manager2.getTransaction().begin(); Conta x = manager1.find(Conta.class, 1L); // x: saldo = 2000 x.setSaldo(x.getSaldo() + 500); // x: saldo = 2500 Conta y = manager2.find(Conta.class, 1L); // y: saldo = 2000 y.setSaldo(y.getSaldo() - 500); // y: saldo = 1500 manager1.getTransaction().commit(); // Conta 1: saldo = 2500 manager2.getTransaction().commit(); // Conta 1: saldo = 1500

Nesse caso, o saldo nal seria 1500 reais.

6.4

Exerccios

8. Acrescente no pacote modelo uma classe para denir contas bancrias.


1 2 3 4 5 6 7 8 9 10 11 @Entity public class Conta { @Id @GeneratedValue private Long id; private double saldo; // GETTERS AND SETTERS }

91

K19 Treinamentos

Tpicos Avanados 9. Adicione uma classe no pacote testes para cadastrar uma conta no banco de dados.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

public class AdicionaConta { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); Conta c = new Conta(); c.setSaldo(2000); manager.persist(c); manager.getTransaction().commit(); manager.close(); factory.close(); } }

Execute e verique a tabela Conta

10. Simule o problema de concorrncia entre Entity Managers adicionando a seguinte classe no pacote testes.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

public class TestaAcessoConcorrente { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager1 = factory.createEntityManager(); EntityManager manager2 = factory.createEntityManager(); manager1.getTransaction().begin(); manager2.getTransaction().begin(); Conta conta1 = manager1.find(Conta.class, 1L); conta1.setSaldo(conta1.getSaldo() + 500); Conta conta2 = manager2.find(Conta.class, 1L); conta2.setSaldo(conta2.getSaldo() - 500); manager1.getTransaction().commit(); manager2.getTransaction().commit(); manager1.close(); factory.close(); } }

Execute e verique que o saldo da conta com identicador 1 termina com 1500 sendo que o correto seria 2000 www.k19.com.br 92

Tpicos Avanados

6.5

Locking Otimista

Para solucionar o problema da concorrncia entre Entity Managers, podemos aplicar a idia de Locking Otimista. Nessa abordagem, um atributo para determinar a verso dos registros acrescentado na entidade. Esse atributo deve ser anotado com @V ERSION.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Entity public class Conta { @Id @GeneratedValue private Long id; private double saldo; @Version private Long versao; // GETTERS AND SETTERS }

Toda vez que um Entity Manager modica um registro da tabela correspondente classe C ONTA, o campo referente ao atributo anotado com @V ERSION incrementado. Agora, antes de modicar um registro da tabela referente classe C ONTA, os Entity Managers comparam a verso do registro no banco de dados com a do objeto que eles possuem. Se as verses forem a mesma signica que nenhum outro Entity Manager modicou o registro, ento as modicaes podem ser executadas sem problemas. Caso contrrio, se as verses forem diferentes signica que algum outro Entity Manager modicou o registro, ento as modicaes so abortadas e uma exception lanada. Em geral, as aplicaes devem capturar essa exception e tentar refazer a operao.

6.6

Exerccios

11. Acrescente um atributo na classe C ONTA anotado com @V ERSION.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Entity public class Conta { @Id @GeneratedValue private Long id; private double saldo; @Version private Long versao; // GETTERS AND SETTERS }

12. Apague a tabela Conta atravs do MySQL Query Browser. 93 K19 Treinamentos

Tpicos Avanados 13. Execute a classe AdicionaConta e verique a tabela Conta atravs do MySQL Query Browser.

14. Execute a classe TestaAcessoConcorrente e observe a exception gerada pelo segundo Entity Manager.

6.7

Locking Pessimista

Outra abordagem para lidar com o problema da concorrncia entre Entity Managers o Locking Pessimista. Nessa abordagem, um Entity Manager pode "travar"os registros fazendo com que os outros Entity Manager que desejem manipular os mesmos registros tenham que aguardar. H vrias maneiras de utilizar o locking pessismista. Uma delas passar mais um parmetro quando um objeto buscado atravs do mtodo FIND ().
1 Conta x = manager.find(Conta.class, 1L, LockModeType.PESSIMISTIC_WRITE);

Uma grande diculdade em utilizar locking pessismista que podemos gerar um deadlock. Suponha que dois Entity Manager busquem o mesmo objeto na mesma thread utilizando o locking pessismista como mostra o cdigo a seguir.
1 2 3 Conta x = manager1.find(Conta.class, 1L, LockModeType.PESSIMISTIC_WRITE); Conta y = manager2.find(Conta.class, 1L, LockModeType.PESSIMISTIC_WRITE); manager1.commit();// NUNCA VAI EXECUTAR ESSA LINHA

Na linha 1, o primeiro Entity Manager "trava"a conta com identicador 1 e esse objeto s ser liberado na linha 3. Na linha 2, o segundo Entity Manager vai esperar o primeiro liberar o objeto impedindo que a linha 3 seja executada. Dessa forma, a linha 3 nunca ser executada. Depois, de um certo tempo esperando na linha 2, o segundo Entity Manager lana uma exception.

6.8

Exerccios

15. Teste o problema de deadlock quando utilizado o locking pessimista. Adicione a seguinte classe no pacote testes. www.k19.com.br 94

Tpicos Avanados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class TestaDeadLock { public static void main(String[] args) { EntityManagerFactory factory = Persistence .createEntityManagerFactory("K21_topicos_avancados"); EntityManager manager1 = factory.createEntityManager(); EntityManager manager2 = factory.createEntityManager(); manager1.getTransaction().begin(); manager2.getTransaction().begin(); manager1.find(Produto.class, 100L, LockModeType.PESSIMISTIC_WRITE); manager2.find(Produto.class, 100L, LockModeType.PESSIMISTIC_WRITE); manager1.getTransaction().commit(); manager2.getTransaction().commit(); manager1.close(); manager2.close(); factory.close(); } }

Execute e aguarde at ocorrer uma exception

6.9

Callbacks

Podemos monitorar o ciclo de vida dos objetos das entidades da nossa aplicao. Certos eventos podem ser capturados e possvel associar um determinado mtodo (callback) a esses eventos. Veja os eventos na listagem abaixo:

PrePersist e PostPersist: Antes e Depois de um objeto ser persistido.

PreRemove e PostRemove: Antes e Depois de um objeto ser removido.

PreUpdate and PostUpdate: Antes e Depois de um objeto ser atualizado no banco de dados.

PostLoad: Depois de um objeto ser carregado do banco de dados.

Os mtodos de callback, ou seja, os mtodos que sero chamados nos eventos acima listados so denidos nas classes das entidades da nossa aplicao e anotados com @P RE P ER SIST , @P OST P ERSIST , @P RE R EMOVE , @P OST R EMOVE , @P RE U PDATE , @P OST P ERSIST e @P OST L OAD. 95 K19 Treinamentos

Tpicos Avanados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Entity public class Produto { @Id @GeneratedValue private Long id; private String nome; private Double preco;

@PrePersist public void prePersist(){ System.out.println("Persistindo...."); } @PostPersist public void postPersist(){ System.out.println("J persistiu...."); }

// GETTERS E SETTERS }

6.10

Exerccios

16. Acrescente dois mtodos de callback na classe P RODUTO.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Entity public class Produto { @Id @GeneratedValue private Long id; private String nome; private Double preco;

@PrePersist public void prePersist(){ System.out.println("Persistindo...."); } @PostPersist public void postPersist(){ System.out.println("J persistiu...."); }

// GETTERS E SETTERS }

17. Execute a classe P OPULA BANCO novamente e observe o console. 18. (Opcional) Teste os outros callbacks. www.k19.com.br 96

Tpicos Avanados

6.11

Consultas Nativas

Os provedores JPA tambm devem oferecer o suporte consultas nativas, ou seja, consultas denidas em SQL. Contudo, devemos lembrar que consultas denidas em SQL so especcas de um determinado banco de dados e eventualmente podem no funcionar em bancos de dados diferentes.
1 2 3 String sql = "SELECT * FROM Procuto"; Query nativeQuery = manager.createNativeQuery(sql, Produto.class); List<Produto> produtos = nativeQuery.getResultList();

6.12

Exerccios

19. Testes as consultas nativas. Acrescente a seguinte classe no pacote testes.


1 2 3 4 5 6 7 8 9 10 11 public class TesteConsultaNativas { public static void main(String[] args) { String sql = "SELECT * FROM Produto"; Query nativeQuery = manager.createNativeQuery(sql, Produto.class); List<Produto> produtos = nativeQuery.getResultList(); for (Produto p : produtos) { System.out.println(p.getNome()); } } }

97

K19 Treinamentos

Tpicos Avanados

www.k19.com.br

98

Captulo 7 Arquitetura
7.1 Inicializao do JPA

O servio de persistncia denido pela especicao JPA deve ser inicializado antes de ser utilizado. O processo de inicializao pode ser realizado pela prpria aplicao ou por Containers Java EE. Quando a aplicao standalone (Java SE), ela prpria deve inicializar o servio de persistncia. Quando a aplicao no standalone (Java EE), a inicializao pode ser feita pela prpria aplicao ou pelo Container Java EE.

7.1.1

Aplicaes Java SE

As aplicaes Java SE (standalone) devem inicializar o servio de persistncia antes de utiliz-lo. A especicao JPA dene a classe P ERSISTENCE que possui um mtodo esttico de inicializao (bootstrap). Esse mtodo deve ser chamado pelas aplicaes Java para que processo de inicializao do servio de persistncia seja executado.
1 EntityManagerFactory factory = Persistence.createEntityManagerFactory("unidade");

A execuo do mtodo CREATE E NTITY M ANAGER FACTORY () custosa pois ele realiza um processo complexo de inicializao. Esse mtodo deve ser chamado apenas uma vez a cada execuo da aplicao. Execut-lo duas ou mais vezes implica em desperdicio dos recursos computacionais o que prejudica o desempenho da aplicao. Para evitar que o mtodo CREATE E NTITY M ANAGER FACTORY () seja executa mais do que uma vez a cada execuo da aplicao, podemos realizar a chamada desse mtodo dentro de um bloco static. O cdido de um bloco static executado quando a classe na qual ele est denido carregada na memria pela mquina virtual. O carregamento de uma classe realizado no mximo uma vez a no ser que a prpria aplicao explicitamente faa um novo carregamento. 99

Arquitetura
1 2 3 4 5 6 7 class JPAUtil { // bloco static static { Persistence.createEntityManagerFactory("unidade"); } }

Alm disso, para disponibilizar globalmente para a aplicao a factory criada pelo mtodo podemos armazenar a referncia dela em um atributo static e criar um mtodo de acesso.
CREATE E NTITY M ANAGER FACTORY (),
1 2 3 4 5 6 7 8 9 10 11 12 13 class JPAUtil { private static EntityManagerFactory factory; // bloco static static { JPAUtil.factory = Persistence.createEntityManagerFactory("unidade"); } public EntityManagerFactory getFactory(){ return JPAUtil.factory; } }

7.1.2

Aplicaes Java EE

As aplicaes Java EE podem gerenciar a inicializao do servio de persistncia ou deixar essa tarefa para o Container Java EE no qual ela est implantada. Para exemplicar, suponha uma aplicao Java Web implantada em um Container Java EE. Geralmente, quando uma aplicao Java Web gerencia a inicializao do servio de persistncia, ela utiliza um ltro para realizar esse gerenciamento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class JPAFilter implements Filter { private EntityManagerFactory factory; public void init(FilterConfig filterConfig) throws ServletException { this.factory = Persistence.createEntityManagerFactory("unidade"); } public void destroy() { this.factory.close(); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // implementao } }

Os mtodos INIT () e DESTROY () so chamados apenas uma vez a cada execuo da aplicao. O INIT () e chamado no comeo da execuo e o DESTROY () no nal. O ltro acima inicializa o servio de persistncia no mtodo INIT () e o encerra no mtodo DESTROY (). www.k19.com.br 100

Arquitetura Alm disso, a aplicao deve gerenciar diretamente as transaes e portanto congurar o arquivo persistence.xml aplicando o valor RESOURCE_LOCAL para a propriedade transactiontype da unidade de persitncia.
1 <persistence-unit name="copadomundo" transaction-type="RESOURCE_LOCAL">

Por outro lado, quando uma aplicao Java Web deixa o Container Java EE no qual ela est implantada gerenciar a inicizalio do servio de persistncia, ela deve congurar o arquivo PERSISTENCE . XML de maneira diferente. A unidade de persistncia deve utilizar transaes do tipo JTA. Esse tipo de transao o padro para aplicaes Java EE. Dessa forma, podemos denir explicitamente esse tipo de transao ou simplesmente no denir nenhum tipo.
1 <persistence-unit name="copadomundo" transaction-type="JTA">

<persistence-unit name="copadomundo">

Alm disso, um data source previamente congurado no Container Java EE deve ser congurado na unidade de persistncia.
1 <jta-data-source>jdbc/MySQL</jta-data-source>

7.2

Repositrios

Todo o controle do ciclo de vida das instncias das entidades e todas as consultas podem ser realizadas atravs dos mtodos da interface dos Entity Managers. Dessa forma, possvel desenvolver uma aplicao utilizando a seguinte abordagem: Quando alguma classe necessita acessar ou modicar os dados das instncias das entidades ela deve obter um Entity Manager e interagir diretamente com ele. Essa abordagem vlida e para muitos casos no prejudicar o desenvolvimento e manuteno da aplicao, ou seja, no h problemas em adot-la. Contudo, algumas condies podem tornar essa abordagem problemtica. Por exemplo, determinada consulta especca da nossa aplicao pode ser complexa demais ou at mesmo impossvel de ser implementada apenas com os mecanismos de pesquisa do JPA (JPQL e Criteria). Nesses casos, a alternativa imediata fazer uma ou mais consultas auxiliares atravs de um Entity Manager e depois realizar um ps processamento nos dados obtidos para gerar o resultado da consulta principal. Supondo que nmero de consultas que exigam um ps processamento considervel, faz sentido pensar em centraliz-las para evitar repetio de cdigo, facilitar a manuteno e viabilizar os testes. Da surge um padro de projeto chamado Repository. Os repositrios so objetos que oferecem acesso s instncias das entidades para toda a aplicao e portanto encapsulam a lgica do controle do ciclo de vida das instncias das entidades e das consultas. De fato, o padro Repository mais vantagoso quando essa lgica mais complexa. 101 K19 Treinamentos

Arquitetura Contudo, podemos padronizar as nossas aplicaes e sempre utilizar o padro Repository para controlar o ciclo de vida das instncias da entidades e realizar as consultas mesmo quando a lgica para essas tarefas simples. Dessa forma, os repositrios sempre funcionariam como uma casca envolvendo os Entity Managers do JPA. Resumidamente, temos trs abordagens para manipular as instncias das entidades e realizar as consultas:

1. Utilizar diretamente os Entity Managers. 2. Utilizar os Entity Managers para os casos mais simples e os Repositrios para os mais complexos. 3. Utilizar sempre os Repositrios como casca dos Entity Managers.

7.3

Controle de Transaes

H diversas abordagens para controlar transaes. A primeira abordagem seria criar uma transao por operao.
1 2 3 manager.getTransaction().begin(); manager.persist(livro); manager.getTransaction().commit();

Adicionando o cdigo necessrio para rollback.


1 2 3 4 5 6 7 8 9 10 11 12 13 EntityTransaction transaction = null; try { transaction = manager.getTransaction(); transaction.begin(); manager.persist(livro); transaction.commit(); } catch(Exception ex) { if(transaction != null && transaction.isActive()) { transaction.rollback(); } } finally { manager.close(); }

O custo para abrir, manter, conrmar e desfazer uma transao relativamente alto. Portanto, a abordagem de criar uma transao por operao pode prejudicar a performance da aplicao. Alm disso, o cdigo para um controle de transaes adequado complexo e no prtico nem seguro replic-lo por toda a aplicao. Podemos melhorar o controle de transaes centralizando o processo em uma classe capaz de executar qualquer trecho de cdigo dentro de uma transao. www.k19.com.br 102

Arquitetura
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public abstract class TarefaTransacional { private EntityManager manager; public TarefaTransacional(EntityManager manager) { this.manager = manager; } public void executa() { EntityTransaction transaction = null; try { transaction = this.manager.getTransaction(); transaction.begin(); this.blocoTransacional(); transaction.commit(); } catch(Exception ex) { if(transaction != null && transaction.isActive()) { transaction.rollback(); } } finally { this.manager.close(); } } public abstract void blocoTransacional(); }

Podemos utilizar a classe TAREFAT RANSACIONAL toda vez que necessrio executar um bloco de cdigo dentro de uma transao.

1 2 3 4 5 6 7

TarefaTransacional tarefa = new TarefaTransacional(manager) { public void blocoTransacional(){ this.manager.persist(livro); this.manager.persist(editora); } } tarefa.executa();

7.3.1

Open Session in View

Um padro muitas vezes adotado para realizar o controle de transaes o Open Session in View. Aplicando esse padro, obtemos um controle centralizado e um nico ponto da aplicao e transparente para todo o resto do cdigo. Em aplicaes Java Web esse padro pode ser aplicado atravs de um ltro. 103 K19 Treinamentos

Arquitetura
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class JPAFilter implements Filter { private EntityManagerFactory factory; public void init(FilterConfig filterConfig) throws ServletException { this.factory = Persistence.createEntityManagerFactory("unidade"); } public void destroy() { this.factory.close(); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { EntityTransaction transaction = null; try { EntityManager manager = this.factory.createEntityManager(); request.setAttribute("em", entityManager); transaction = manager.getTransaction(); transaction.begin(); chain.doFilter(request, response); transaction.commit(); } catch(Exception ex) { if(transaction != null && transaction.isActive()) { transaction.rollback(); } } finally { manager.close(); } } }

Nessa abordagem, todas as requisies so processadas dentro de uma nica transao.

www.k19.com.br

104

You might also like