Professional Documents
Culture Documents
2 Semestre - 2010
http://java.sun.com/javaee/technologies/persistence.jsp
Conceitos
Parte integrante da JavaEE 5 Disponvel a partir da Java5 Definida na JSR220 Enterprise JavaBeans 3.0 Padroniza o Mapeamento Objeto Relacional No depende de Container para funcionar Baseada no conceito de POJOs (Plain Old Java Object) Utiliza amplamente Annotations (Progamao Declarativa) Pacote javax.persistence
3
Entidades Os objetos persistentes so denominados Entities(Entidades) As Classes de Entidades devem atender a alguns requisitos: Ser anotadas com a anotao javax.persistence.Entity Possuir um identificador(chave primria) a no ser que seja uma subclasse. Possuir um construtor public ou protected sem parmetros (podem ter outros construtores). No podem ser declaradas como final. Mtodos ou variveis de instncia no podem ser declarados como final. Se forem passados como parmetro em uma chamada de mtodo remota, a classe precisa implementar a interface java.io.Serializable.
9
Outros tipos serializveis como: Wrappers de tipos primitivos, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.TimeStamp, tipos serializveis definidos pelo usurio, byte[], Byte[], char[], Character[], tipos enumerados, outras entidades e/ou colees de entidades, classes "embeddable". Outras entidades e/ou Colees de entidades. Classes embutidas (Embeddable)
O mapeamento do estado das entidades feito com anotaes, ou nos campos persistentes, ou ento nos mtodos getters, nunca em ambos, em uma nica entidade.
11
Unidade de Persistncia (Persistence Unit) Conjunto de classes mapeadas para um banco de dados
12
javax.persistence.EntityManager
Servio que gerenciar o conjunto de entidades registradas dentro de um contexto. Monitorando as alteraes feitas nos objetos deste contexto de persistncia, gravando assim essas alteraes no banco de dados. Provedor de Persistncia (Persistence Provider) como se fosse um driver JPA para uma determinada ferramenta de mapeamento objeto-relacional. Mais especificamente, a classe que implementa a interface javax.persistence.PersistenceProvider So alguns exemplos de fornecedores de provedores de persistncia:
Arquitetura
Aplicao Java
API JDBC
Driver JDBC
Banco De Dados
14
Objeto no existe
new find( )
DETACHED
NEW
merge( ) persist( )
MANAGED
remove( )
Garbage Collector
15
REMOVED
JPA - Mapeamento
As classes e interfaces da JPA esto localizadas no pacote javax.persistence. A API faz uso intensivo de anotaes (As anotaes surgiram da verso 5.0 do Java e esto presentes na maioria das APIs do novo JEE), por isso no necessrio criar descritores XML para cada uma das entidades da aplicao (Mesmo no sendo obrigatrio o uso de XML para descrever o mapeamento, ainda possvel utilizar essa opo. Um exemplo tpico o arquivo persistence.xml, que guarda as configuraes da unidade de persistncia. Uma entidade uma classe Java comum, rotulada atravs da anotao @Entity. No preciso implementar interfaces ou estender outras classes para tornar uma classe persistvel; a nica exigncia que a classe da entidade possua um construtor sem parmetros, pois a instanciao da classe feita por reflexo.
16
@Id Define o atributo que constitui a chave primria. @GeneratedValue Define um campo auto-incremento. @Column Define o nome da coluna onde o atributo ser salvo. @Temporal Fornece informaes adicionais ao provedor de
persistncia sobre o mapeamento de um atributo do tipo java.util.Date ou java.util.Calendar. Utiliza os valores
TemporalType.DATE, TemporalType.TIME ou TemporalType.TIMESTAMP.
JPA - Mapeamento
No cdigo a seguir a classe Pessoa representa uma entidade. O atributo cpf o identificador da entidade (chave primria), especificado atravs da anotao @Id: @Entity public class Pessoa { @Id private String cpf; }
18
JPA - Mapeamento
Grande parte da produtividade trazida pela JPA deve-se utilizao de valores default de mapeamento, que facilitam bastante o trabalho do desenvolvedor. Assim, o que no definido explicitamente assume a configurao padro da API. Por exemplo, por padro a JPA considera o nome da entidade o mesmo nome da tabela no banco de dados e o nome da propriedade o mesmo nome da coluna. No cdigo anterior, a entidade Pessoa ser salva na tabela PESSOA e a propriedade cpf na coluna CPF. Caso seja necessrio alterar a forma de mapeamento, devem-se utilizar as anotaes @Table e @Column, por exemplo: @Entity @Table(name=TB_PESSOA) public class Pessoa { @Id @Column(name=DS_CPF) private String cpf; }
19
JPA Mapeamento
Outro padro utilizado pelo JPA considerar todas as propriedades de uma entidade como persistentes (o mapeamento segue as regras descritas anteriormente). Caso seja desejvel excluir alguma propriedade do mapeamento (ex.: no caso de ela poder ser criada a partir de outras propriedades), basta marc-la com a anotao @Transient: @Entity public class Pessoa { @Id private String cpf; @Transient private String nomeCompleto; }
20
Exemplo de Entidade
import javax.persistence.*;
@Entity @Table(name = "Aluno") public class Aluno { @Id @GeneratedValue (strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false, columnDefinition = "integer")
Exemplo de Entidade
import javax.persistence.*; import java.util.*; @Entity @Table (name = "Pessoa") public class Pessoa { @Id
@GeneratedValue (strategy=GenerationType.IDENTITY)
@Column (name = "id", nullable = false, columnDefinition = "integer") private int id; @Column (name = "nome", length = 50, nullable = false) private String nome; @Column (name = "dataNasc") @Temporal (TemporalType.DATE) private Date dataNasc; //getters e setters omitidos
22
import java.util.*;
@Entity public class Pessoa { @Id @GeneratedValue private int id; private String nome;
@Temporal (TemporalType.DATE)
private Date dataNasc; //getters e setters omitidos } 24
Criar um Gerenciador de Entidades atravs de uma fbrica: EntityManagerFactory emf = Persistence.createEntityManagerFactory("unidade"); EntityManager em = emf.createEntityManager(); Iniciar uma Transao: em.getTransaction().begin(); Criar uma Entidade: Entidade e = new Entidade(); Persistir uma Entidade: em.persist(e); Localizar uma Entidade: Entidade e = em.find(Entidade.class, chave); Sincronizar uma Entidade: e = em.merge(e); Eliminar uma Entidade: em.remove(e); Encerrar uma Transao: em.getTransaction().commit(); 25
Interface EntityManager
(alguns mtodos)
EntityTransaction getTransaction( )
Retorna a transao do EntityManager.
Interface EntityManager
(alguns mtodos)
void begin( )
Inicia uma transao.
void commit( )
Encerra uma transao, gravando quaisquer alteraes no banco de dados.
void rollback( )
Desfaz quaisquer alteraes desde o incio da transao.
27
Coloque o arquivo baixado em uma pasta de trabalho e execute o seguinte comando nesta pasta: java -jar glassfish-persistence-installer-v2-bXX.jar Isto ir criar uma pasta chamada glassfish-persistence contendo o arquivo de licena, README e as bibliotecas TopLink Essentials: 3RD-PARTY-LICENSE.txt CDDLv1.0.txt README toplink-essentials-agent.jar toplink-essentials.jar
28
Crie um projeto (Java5 ou superior) e adicione os arquivos .jar mencionados anteriormente, no classpath, para que se possa utilizar o Oracle TopLink. No esquea de adicionar tambm o .jar do driver JDBC. Crie a classe persistente chamada Aluno descrita abaixo: package modelo; import javax.persistence.*; @Entity public class Aluno { @Id @GeneratedValue (strategy=GenerationType.IDENTITY) private int id; private String nome; private long ra; private double ms1; private double ms2; //getters e setters omitidos }
29
<?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" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="teste"> <provider> oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider </provider> <class>modelo.Aluno</class> <properties> <property name="toplink.logging.level" value="INFO" /> <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver" />
30
31
package negocio;
import modelo.*; import javax.persistence.*; public class CriaAluno { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("teste"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Aluno a = new Aluno(); a.setNome("Maria"); a.setRa(123456789); a.setMs1(5.5); a.setMs2(4.5); em.persist(a); //Torna o objeto MANAGED em.getTransaction().commit(); em.close(); emf.close(); System.out.println("id do aluno persistido: " + a.getId()); } } 32
Implantao da Aplicao.
Na pasta raiz do seu projeto, crie um arquivo texto chamado manifest.txt com o seguinte contedo:
No prompt de comando, na pasta raiz do seu projeto, digite a seguinte linha de comando: jar cvfm teste.jar manifest.txt *.class model/*.class META-INF/*
Ser gerado um arquivo chamado teste.jar que contm as classes da aplicao. Copie os arquivos .jar do Oracle TopLink e o .jar do driver JDBC para a pasta onde estiver o arquivo teste.jar.
Para executar a aplicao, digite a seguinte linha de comando: java -jar teste.jar
33
Baixe o Ant (arquivo: apache-ant-1.7.0-bin.zip) do site: http://ant.apache.org Descompacte o arquivo na pasta raiz do hd. Renomeie a pasta para "ant".
Crie uma varivel de ambiente chamada "ANT_HOME" contendo o caminho da pasta de instalao do ant:
"set ANT_HOME=c:\ant"
35
Integrando o ANT com o Eclipse Selecione o menu "Project"; Selecione "properties"; Selecione "Builders"; Clique em "new"; Escolha "Ant Build"; Em "Name Buildfile" clique em xxx e selecione o arquivo de build criado anteriormente; Com o build selecionado clique no boto "up" at que o "ant build" aparea em primeiro lugar na lista.
37
38
package negocio; import modelo.*; import javax.persistence.*; public class ExcluiAluno { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("teste"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Aluno a = em.find(Aluno.class, 8); if (a != null) { em.remove(a); /*Objeto torna-se REMOVED, qualquer alterao no ser refletida no banco de dados.*/ System.out.println("Aluno excludo: " + a.getId()); System.out.println(" " + a.getNome()); } else { System.out.println("Aluno no encontrado"); } em.getTransaction().commit(); em.close(); emf.close(); } }
40
package negocio; import modelo.*; import javax.persistence.*; public class SincronizaAluno { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("teste"); EntityManager em = emf.createEntityManager(); Aluno a = em.find(Aluno.class, 9); em.close(); if (a != null) { System.out.println("Nome: " + a.getNome()); a = mudaDados(a); em = emf.createEntityManager(); em.getTransaction().begin(); em.merge(a); //Sincroniza o estado da entidade no banco de dados em.getTransaction().commit(); System.out.println("Novo Nome: " + a.getNome()); } else { System.out.println("Aluno no encontrado"); } } private static Aluno mudaDados(Aluno a) { a.setNome("Juliana"); return a; } }
Sincronizao - Localiza uma entidade atravs da chave primria, encerra o EntityManager, altera o estado da entidade e a sincroniza no banco de dados.
41
43
mapeamento, a tabela do banco de dados requer uma coluna discriminadora, cujo nome
definido pela anotao @DiscriminatorColumn. Essa coluna usada para identificar o tipo da entidade sendo armazenado em uma linha da tabela. O tipo dessa coluna definido atravs do atributo DiscriminatorType que pode ser STRING (valor padro), CHAR ou INTEGER. O valor dessa coluna definido atravs da anotao @DiscriminatorValue. Se omitir a anotao @DescriminatorColumn, o nome padro para a coluna discriminadora ser DTYPE. Se omitir a anotao @DiscriminatorValue, o valor padro da coluna ser o nome da
entidade caso o tipo seja STRING, para os outros tipos, o provedor de persistncia gera
um valor automaticamente. Nas subclasses, no necessrio nenhum mapeamento de herana, a no ser que se queira alterar o valor do discriminador.
44
Exemplo de superclasse:
package modelo; import javax.persistence.*; import java.util.* ; @Entity @Table(name = "Pessoa_Hierarquia") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING) @DiscriminatorValue("PESSOA") public class Pessoa { @Id @GeneratedValue private int id ; private String nome; @Temporal(TemporalType.DATE) private Date dataNasc; //getters e setters }
45
Exemplo de subclasse:
// No esquecer de mapear o arquivo persistence.xml
package modelo;
import javax.persistence.*; @Entity
@DiscriminatorValue("ALUNO")
public class Aluno extends Pessoa { int ra;
String turma;
// getters e setters }
46
Vantagens
A estratgia de mapeamento SINGLE_TABLE a mais simples de
Desvantagens
Todas as colunas das propriedades de subclasse precisam ser nulveis. Portanto, se precisar definir quaisquer restries NOT NULL nessas colunas, no ser permitido. Dependendo do tipo de entidade, haver colunas noutilizadas. Essa estratgia no normalizada. 47
Uma tabela de banco de dados definida para cada classe concreta na hierarquia. Cada tabela tem colunas que representam suas propriedades e todas as propriedades de quaisquer super-classes.
Vantagens
A vantagem dessa estratgia em relao SINGLE_TABLE que se pode definir restries nas propriedades das subclasses. Tambm pode ser mais fcil mapear o esquema de dados legado.
Desvantagens
Nessa estratgia, as tabelas no so normalizadas, pois possuem colunas redundantes. Uma forma de se implementar essa estratgia utilizar o comando SQL Union, o que nem todos os bancos de dados suportam.
48
propriedades definidas nessa classe particular. semelhante estratgia TABLE_PER_CLASS, exceto pelo esquema ser normalizado.
Nessa estratgia, deve haver uma coluna em cada tabela que possa ser utilizada para unir cada tabela. O nome dessa coluna definido atravs da anotao @PrimaryKeyJoinColumn pelo atributo name. Se essa anotao for omitida, por padro, assumido o mesmo nome da coluna de chave primria da superclasse. Nas subclasses, o atributo referencedColumnName da anotao @PrimaryKeyJoinColum define a coluna da superclasse utilizada para realizar a juno. Se omitir a anotao @DescriminatorColumn na superclasse, o nome padro para a coluna discriminadora ser DTYPE.
49
Vantagens
Embora no seja to rpido quanto a estratgia SINGLE_TABLE, consegue-se definir restries NOT NULL em qualquer coluna de qualquer tabela, e seu modelo normalizado. Esse mapeamento possui um melhor desempenho que a estratgia TABLE_PER_CLASS se SQL UNIONs no forem suportadas.
Desvantagens
No possui um desempenho to rpido quanto SINGLE_TABLE.
50
Consultas
As consultas so criadas usando-se tanto a linguagem de consulta EJB Query Language (tambm chamada de JPA QL) como a SQL nativa. A EJB QL semelhante SQL, s que orientada a objetos e portvel para diferentes implementaes de bancos de dados. So executadas por meio da interface javax.persistence.Query que muito parecida com a interface java.sql.PreparedStatement. Essa interface Query obtida em tempo de execuo a partir do gerenciador de entidade. As consultas podem ser criadas dinamicamente em tempo de execuo ou pr-declaradas por meio de anotaes nas classes persistentes ou atravs de XML.
51
Interface Query
(javax.persistence.Query)
Alguns Mtodos
List getResultList ( ) Executa uma consulta e retorna uma coleo de resultados. Object getSingleResult ( ) Executa uma consulta e retorna um nico resultado. int executeUpdate ( ) Executa um comando de atualizao(insert, update ou delete) e retorna o nmero de linhas afetadas no banco de dados. Query setMaxResults (int mximo) Define o nmero mximo de entidades que deve ser retornado na consulta.
52
Query setFirstResult (int incio) Define o nmero da linha inicial que ir compor o resultado da consulta. void setParameter (String nome, Object valor) Define o valor de um parmetro atravs de seu nome. Query setParameter (String nome, Date valor, TemporalType tipo) Define o valor de um parmetro do tipo data atravs de seu nome. Query setParameter (int posio, Object valor) Define o valor de um parmetro atravs de sua posio. Query setParameter (int posio, Date valor, TemporalType tipo) Define o valor de um parmetro do tipo data atravs de sua posio.
53
Consultas Dinmicas
So criadas pelo gerenciador de entidades atravs do mtodo createQuery().
try { Query consulta = em.createQuery( "Select a from Aluno a where a.ra = :ra"); consulta.setParameter("ra", 123456789); Aluno a = (Aluno) consulta.getSingleResult(); System.out.println("RA: " + a.getRa()); System.out.println("Nome: " + a.getNome()); } catch(NoResultException ex) { System.out.println("Aluno no encontrado"); } catch(NonUniqueResultException ex) { System.out.println("Mais que um resultado encontrado"); }
54
Os parmetros da consulta so ajustados atravs do mtodo setParameter( ) e podem ser indicados atravs de duas formas:
Query consulta = em.createQuery( "Select a from Aluno a where a.ra = :ra and a.nome = :nome ); consulta.setParameter("ra", 123456789); consulta.setParameter("nome", "Maria");
Query consulta = em.createQuery( "Select a from Aluno a where a.ra = ?1 and a.nome = ?2 ) consulta.setParameter(1, 123456789); consulta.setParameter(2, "Maria");
55
public class BuscaPorRA { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("teste"); EntityManager em = emf.createEntityManager(); try { Query consulta = em.createQuery("Select a from Aluno a where a.ra = :ra"); consulta.setParameter("ra", 123456789); Aluno a = (Aluno)consulta.getSingleResult(); System.out.println("RA: " + a.getRa()); System.out.println("Nome: " + a.getNome()); } catch(NoResultException ex) { System.out.println("Aluno no encontrado"); } catch(NonUniqueResultException ex) { System.out.println("Mais que um resultado encontrado"); } em.close(); emf.close(); } }
56
Query consulta = em.createQuery( "Select a from Aluno a where a.ms1 > :media"); consulta.setParameter("media", 5); List <Aluno>alunos = consulta.getResultList(); if (!alunos.isEmpty()) { for (Aluno a : alunos) { System.out.println("Nome: " + a.getNome()); } } else { System.out.println("Alunos no encontrados"); }
57
58
59
Query consulta = em.createQuery( "Select a from Aluno a where a.DataMatricula = :data"); consulta.setParameter("data", new java.util.Date, TemporalType.DATE); List <Aluno>alunos = consulta.getResultList(); if (!alunos.isEmpty()) { for (Aluno a : alunos) { System.out.println("Nome: " + a.getNome()); } } else { System.out.println("Alunos no encontrados"); }
60
Consulta utiliza um
61
public static List getAlunos(int maximo, int inicio) { Query consulta = em.createQuery("Select a from Aluno a"); return consulta.setMaxResults(maximo). setFirstResult(inicio). getResultList(); }
62
public static List getAlunos(int maximo, int inicio) { Query consulta = em.createQuery("Select a from Aluno a"); return consulta.setMaxResults(maximo). setFirstResult(inicio). getResultList(); }
63
So consultas pr-definidas na classe da entidade e podem ser reutilizadas em diferentes pontos da sua aplicao, facilitando assim sua manuteno. So declaradas atravs das anotaes @NamedQueries(define um array de consultas nomeadas) e @NamedQuery(define uma consulta nomeada). So criadas pelo gerenciador de entidades atravs do mtodo createNamedQuery().
Na entidade
Na aplicao
@NamedQueries({ @NamedQuery(name = "consultaPorRA", query = "Select a from Aluno a where a.ra = :ra"), @NamedQuery(name = "consultaPorMedia", query = "Select a from Aluno a where a.ms1 > :media") })
@NamedQueries ( { @NamedQuery (name = "buscaPorRA", query = "Select a from Aluno a where a.ra = :ra"), @NamedQuery (name = "consultaPorTurma", query = "Select a from Aluno a where a.turma = :turma") } )
@Entity public class Aluno extends Pessoa { int ra; String turma; // getters e setters }
66
Alteraes em Lote
So criadas pelo gerenciador de entidades da mesma forma que as consultas. Podem ser tanto dinmicas como nomeadas. So executadas atravs do mtodo executeUpdate() que retorna o nmero de linhas afetadas.
Alterao em lote
public class TransfereTurma { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("teste"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Query alteracao = em.createQuery( "Update Aluno set turma = :novaTurma"); alteracao.setParameter("novaTurma", "as05a.2"); int qtdAlunos = alteracao.executeUpdate(); System.out.println(qtdAlunos + " Alunos transferidos de turma");
em.getTransaction().commit(); em.close(); emf.close();
69
@PrePersist
Define o mtodo a ser executado logo aps a uma chamada de EntityManager.persist().
@PostPersist
Define o mtodo a ser executado aps a insero no banco de dados.
@PostLoad
Define o mtodo a ser executado aps a uma chamada de EntityManager.find(), EntityManager.refresh(), ou quando uma consulta EJB QL executada.
70
@PreUpdate
Define o mtodo a ser executado antes do estado de uma entidade ser sincronizado com o banco de dados.
@PostUpdate
Define o mtodo a ser executado aps o estado de uma entidade ser sincronizado, isso ocorre na confirmao de uma transao, aps uma chamada a EntityManager.flush() ou sempre que o contexto de persistncia atualizar o banco de dados.
@PreRemove
Define o mtodo a ser executado aps a uma chamada de EntityManager.remove().
@PostRemove
Define o mtodo a ser executado aps a excluso no banco de dados ser efetivada.
@Entity public class Aluno { ... @PrePersist void prePersist() { try { FileOutputStream fos = new FileOutputStream("log.txt", true); String linha = "Aluno " + getNome() + " gravado em " + new Date() + "\n"; fos.write(linha.getBytes()); fos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } } 72