domingo, 1 de setembro de 2013

JPA - Hibernate

JPA (Java Persistence API)

 http://www.marcomendes.com/ArquivosBlog/AloMundoJPA.pdf
 http://www.devmedia.com.br/articles/viewcomp.asp?comp=4590
 http://evandropaes.wordpress.com/2007/06/22/introducao-a-java-persistence-api-%E2%80%93-jpa/
 http://www.slideshare.net/caroljmcdonald/td09jpabestpractices2
 http://www.slideshare.net/guestf54162/jpa-java-persistence-api
 http://www.slideshare.net/rodrigocasca/jpa
 https://www.redhat.com/docs/manuals/jboss/jboss-eap-4.2/doc/Server_Configuration_Guide/Java_EE_5_Application_Configuration.html
 http://www.slideshare.net/junyuo/java-persistence-api-jpa-step-by-step-presentation
 
 JPA é um framework utilizado na camada de persistência para obter maior produtividade. Modo padrão de mapeamento Objeto/Relacional.
 O JPA define um caminho para mapear os POJOs para um BD (Java Persistence Metadata). Os pojos são vistos como beans de entidade(Entity Beans).
 Utiliza-se o ORM(Mapeamento Objeto/Relacional) para os entity Beans possam ser portados facilmente de um fabricante para outro.
 
 
 
  Entity: POJO, suporta herança e polimorfismo
 EntityManager: Responsável pelas operações de persistência de objetos.
 PersistenceContext: Área de memória que mantém os objetos que estão sendo manipulados pelos EntityManager
 Provedores: Especificação para framework de persistência.
 Persistence Unit: Configuração do provedor JPA para localizar o banco de dados e estabelecer conexões JDBC.
 
 Exemplo simples:
 package addressbook;
 import javax.persistence.*;
 
 @Entity
 public class Person {
   @Id @GeneratedValue
   public Long id;
   public String first;
   public String middle;
   public String last;
 }
 
 package addressbook;
 import javax.persistence.*;
 
 public class Main {
   EntityManagerFactory factory; //Um factory por aplicação, pois é thread-safe. Mas só é importante para aplicações Web. App desktop só tem 1 usuário mesmo.
   EntityManager manager;       //Um manager por usuário.    
   
   public void init() {
     factory = Persistence.createEntityManagerFactory("sample");//Persistence unit no persistence.xml.
     manager = factory.createEntityManager();
   }
 
   private void shutdown() {
     manager.close();
     factory.close();
   }
   
   public static void main(String[] args) {
     // TODO code application logic here
     Main main = new Main();
     main.init();
     try {
       // do some persistence stuff
     } catch (RuntimeException ex) {
       ex.printStackTrace();
     } finally {
       main.shutdown();
     }
   }
 //Para fazer uma persistência, é só criar uma transação, criar os objetos e salvá-los
   private void create() {
     System.out.println("creating two people");
     EntityTransaction tx = manager.getTransaction(); //Criou a Transação.
     tx.begin();
     try {
       Person person = new Person();
       person.first = "Joshua";
       person.middle = "Michael";
       person.last = "Marinacci";
       manager.persist(person);
 
       tx.commit();
     } catch (Exception ex) {
       tx.rollback();
     }
     System.out.println("created one person");
   }
 }
 
 Chaves compostas usando @EmbeddedId
 @Embeddable
 public class ContactPK implements Serializable {
 
   @Column(name = "FIRSTNAME", nullable = false)
   private String firstname;
 
   @Column(name = "LASTNAME", nullable = false)
   private String lastname;
 }
 A chave primária da classe da Entidade é anotada com a anotação @EmbeddedId.
 @Entity
 public class Contact implements Serializable {
 
   /**
    * EmbeddedId primary key field
    */
   @EmbeddedId
   protected ContactPK contactPK;
 
   public void hashcode(){} // tem que incluir esses dois métodos para garantir que terá só uma chave.
   public void equals() {}
 ...
 }
 
 
 Persistence.xml
 •     Lista as classes a serem persistidas
 •     A conexão do Banco de Dados
 •     E propriedades específicas para a implementação de persistência (ex:Hibernate, Hypersonic)
 •     Deve ficar dentro do META-INF
 
 <?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="sample" transaction-type="RESOURCE_LOCAL"> //Tem o nome da unidade, que tem que ser o mesmo recebido em Persistence.createEntityManagerFactory()
    <class>addressbook.Person</class>
    <properties>
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.connection.password" value=""/>
      <property name="hibernate.connection.url"  value="jdbc:hsqldb:hsql://test"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/> //Controla como o hibernate cria e gerencia as suas tabelas
 o     Validate:
 o     Update: Cria as tabelas se elas não existirem, se adicionar novos campos, altera a tabela, deixando os dados intactos.
 o     Create: Cria a tabela na primeira conexão, destruindo todos os dados anteriores. Bom para teste.
 o     Create-drop: como o Create, mas destroy a tabela quando a conexão é fechada. Bom pra teste de unidade.
    </properties>
   </persistence-unit>
 </persistence>
 
 Rodar
 java -classpath lib/hsqldb.jar org.hsqldb.Server //Para rodar o hypersonic
 
 public static void main(String[] args) throws Exception {
    // start hypersonic
    Class.forName("org.hsqldb.jdbcDriver").newInstance();
    Connection c = DriverManager.getConnection(
         "jdbc:hsqldb:file:test", "sa", "");
    // start persistence
    Main main = new Main();
    main.init();
 
    // rest of the program....
 
   // shutdown hypersonic
   Statement stmt = c.createStatement();
   stmt.execute("SHUTDOWN");
   c.close();
 }
 
 Outros exemplos de Persistence.xml
 http://download.oracle.com/docs/cd/B31017_01/web.1013/b28221/cfgdepds005.htm
      Usado para o servidor saber qual DabaBase será usado. Nele é configurado qual engine de mapeamento Objeto/Relacional, cache para melhor performance. Ele dá a flexibilidade completa para configurar o EntityManager.
 
      Colocar em: META-INF dentro do diretorio WEB-INF/classes ou do Jar.
 OpenJPA
 <?xml version="1.0"?>
 <persistence>
   <persistence-unit name="testjpa" transaction-type="RESOURCE_LOCAL">
     <provider>
       org.apache.openjpa.persistence.PersistenceProviderImpl
     </provider>
     <class>entidades.Cliente</class>
     <properties>
       <property name="openjpa.ConnectionURL" value="jdbc:postgresql://localhost:5432/jpateste"/>
       <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver"/>
       <property name="openjpa.ConnectionUserName" value="postgres"/>
       <property name="openjpa.ConnectionPassword" value="123456"/>
       <property name="openjpa.Log" value="SQL=TRACE"/>
     </properties>
   </persistence-unit>
 </persistence>
 
 Hibernate
 <persistence>
  <persistence-unit name="EmployeeService" transaction-type="RESOURCE_LOCAL">
 
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <jta-data-source>java:/DefaultDS</jta-data-source>
   <properties>
    <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver"/>
    <property name="hibernate.connection.url" value="jdbc:derby:db; create=true"/>
    <property name="hibernate.connection.autocommit" value="true"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" ou “DerbyDialect”/>
    <property name="hibernate.connection.username" value="APP" />
    <property name="hibernate.connection.password" value="APP" />
 
   </properties>
  </persistence-unit>
  OU
 <persistence>
  <persistence-unit name="EmployeeService" transaction-type="RESOURCE_LOCAL">
   <properties>
      <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver" />
      <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true" />
      <property name="hibernate.connection.username" value="APP" />
      <property name="hibernate.connection.password" value="APP" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
 </properties>
  </persistence-unit>
 </persistence>
 
 TopLink
 <persistence>
 <persistence-unit name="EmployeeService" transaction-type="RESOURCE_LOCAL">
  <properties>
      <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
      <property name="toplink.jdbc.user" value="APP"/>
      <property name="toplink.jdbc.password" value="APP"/>
  </properties>
 </persistence-unit>
 </persistence>
 
 
 
 Tabela:
 create table bug (
 id_bug int(11) not null auto_increment,
 titulo varchar(60) not null,
 data date default null,
 texto text not null,
 primary key (id_bug)
 );
 
 Classe POJO
 @entity
 @table(name=”bug”)
 public class bug implements java.io.serializable {
      private integer id_bug;
      private string titulo;
      private java.util.date data;
      private string texto;
      @Enumerated(EnumType.STRING) → Define que um tipo vem de um enum
      @Conumn(name=”TIPO_MOEDA”, nullable=false, columnDefinition=”CHAR(1)”))
      private TipoMoeda tipoMoeda;
      @Transient → Valor não será gravado.
      private Integer valor = new Integer();
      /** creates a new instance of bug */
      public bug() {}
      /*a notação @generatedvalue(strategy=generationtype.sequence) informa que o id será gerado automaticamente pelo db.*/
      @id
      @generatedvalue(strategy=generationtype.sequence)
      @column(name=”id_bug”)
      public integer getid_bug() {     return id_bug;     }
      public void setid_bug(integer id_bug) {     this.id_bug = id_bug;     }
 
      @column(name=”titulo”, lenght=255, nullable=true)
      public string gettitulo() {     return titulo;     }
      public void settitulo(string titulo) {          this.titulo = titulo;     }
 
      @temporal(temporaltype.date)
      @column(name=”data”)
      public java.util.date getdata() {     return data;     }
      public void setdata(java.util.date data) {     this.data = data;     }
 
      @column(name=”texto”)
      @Lob → Define que o campo armazenará dados do tipo Long Object Binary(texto)
      public string gettexto() {     return texto;     }
      public void settexto(string texto) {     this.texto = texto;     }
      @override
      public string tostring(){     return “id: “+this.id_bug;     }
 }
 
 Query
 •     NamedQuery
 o     Query predefinidaes executadas por nome.
 @NamedQuery cria consulta predefinida (estática) associado com o @Entity
 
 @Entity
 @NamedQuery(name = “ConsultaPorId”, query = “SELECT f FROM Funcionarios f WHERE f.id = :id”)
 public class Funcionario implements Serializable {
 ...
 }
 
 •     Criteria
 o     So do Hibernate, baseado na API Criteria
 •     By Example
 •     JPAQL/ HQL / EJB3-QL
 o     Parecidas com SQL, mas mais objec-centric
 o     Suporta (Seleção de instancias, propriedades, polimorfismo), joining automático para propriedades nested.
 o     Confortável para quem é familiar ao SQL
 o     JPAQL é um subconjunto do HQL (Hibernate suporta ambos)
 o     Para rodar:
      EntityManager.createQuery(String jpaql)
      Session.createQuery(String hql)
 Ex: “from Item i where i.name = “aaa”
   private void search() {
     EntityTransaction tx = manager.getTransaction();
     tx.begin();
     System.out.println("searching for people");
     Query query = manager.createQuery("select p from Person p");
     List<Person> results = (List<Person>)query.getResultList();
     for(Person p : results) {
       System.out.println("got a person: " + p.first + " " + p.last);
     }
     System.out.println("done searching for people");
     tx.commit();
   }
 
 
 •     Native SQL
 o     Session.createSQLQuery(SQL)
 o     EntityManager.createNativeQuery(sql)
 
 
 
 Relacionamento
 •     Um para Um (@OneToOne)
 @OneToOne (mapedBy = “pessoa”)
 private Ramal ramal;
 
 @OneToOne
 @JoinColumn( name = “id_pessoa”)
 private Pessoa pessoa;
 Tabelas.
 ramal                    pessoa
  - numero:Integer                - id:Integer
  - pessoa_id: Integer (FK)           - nome: VARCHAR(50)
 
 
 •     Um para Muitos(@OneToMany)´
 Uma entidade possui uma coleção de outras entidades.
 @OneToMany(mappedBy=”pessoa”, cascade = CascadeType.ALL)
 private List<Ramal> ramais = new ArrayLIst<Ramal>();
 •     Muitos para um (@ManyToOne)
 A entidade faz parte de uma coleção de entidades de outra entidade.
 @ManyToOne(cascade=CascadeType.PERSIST)
 @JoinColumn(name=”id_pessoa”)
 private Pessoa pessoa;
 
 •     Muitos para muitos(@ManyToMany)
 @ManyToMany
 @JoinTable(name=”ramal_pessoa”,
 joinColumns=(@JoinColumn(name = “id_pessoa”)),
 inverseJoinColumns = (@JoinColumn(name = “id_ramal”))
 )
 @Column (name = “id_ramal”);
 private List<Ramal> ramais = new ArrayList<Ramal>();
       
 @ManyToMany
 @JoinTable(name=”ramal_pessoa”,
 joinColumns=(@JoinColumn(name = “id_ramal”)),
 inverseJoinColumns = (@JoinColumn(name = “id_pessoa”))
 )
 @Column(name = “id_pessoa”)
 private List<Ramal> pessoas= new ArrayList<Ramal>();
 
 Tabelas:
 Ramal               pessoa_has_ramal                    pessoa
  - numero:INTEGER     - pessoa_id: INTEGER (FK)                - id:INTEGER
                - ramal_numero: INTEGER                - nome: VARCHAR(50)
 
 Características dos Relacionamentos:
 •     Lazy loading
 o     Otimização de Performance
 o     Itens relacionados não são carregados até que eles sejam acessados pela primeira vez. (acesso a nível de Campo)
 o     Limitado para trabalhar somente com a Sessão ou EntityManager que carregou o objeto pai.
      Pode causar problemas em aplicações web.
 •     Fetch
 o     Fetch Mode
      Lazy
      Eager – desabilita o lazy loading
 o     Modo pode ser configurado em cada relacionamento.
 o     Considerar a performance e usar quando estiver configurando o fetch.
 @Basic(fetch = FetchType.LAZY) //Só vai carregar o objeto quando o método for acessado.
 @Lob      //Permite um BLOB ou CLOB (Bit or Char Large Object transforma valores para charS ou biteS
 public BufferedImage getPhoto() {
   return photo;
 }
 
 
 •     Cascading
 o     Fala do Hibernate o que fazer com o relacionamento nos casos de Insert, Update, Delete, All
 o     Cascade=PERSIST, REMOVE, MERGE, REFRESH, ALL.
 •     Polimorphic
 o     Três abordagens:
      Tabela por hierarquia de classe
 •     Todo dado de todas as propriedades das classes na herança são guardadas na tabela.
 •     Requer que as colunas que representam campos na subclasses permitam NULL.
 •     Usa uma coluna discriminadora para determinar o tipo de objeto representado em uma tupla.
 @Entity
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
 @DiscriminatorColumn(name=”person_type”)
 public class Person {
      @Id     @GeneratedValue(strategy=GenerationType.AUTO)
      private int id = 0;
      private String name;
 }
 @Entity @DiscriminatorValue(value=”p”
 public class Patient extends Person {
      private boolean insured = false;
 }
 @Entity @DiscriminatorValue(value=”d”)
 public class Physician extends Person {
      private boolean accredited;
 }
 
 create table person {
      patient_id INTEGER,
      person_type varchar(255) not null,
      name varchar(255) not null,
      insured bit
      accredited bit
      primary key (patient_id));
 
      Tabela por sub-classe.
 •     Cada sub-classe tem a sua própria tabela.
 •     Campos da classe Pai estão em outra tabela.
 •     PK na tabela da sub-classe referem à tabela da classe pai.
 •     Usar configuração joined-subclass
 •     Também suporta o uso de discriminator
 @Entity     @Inheritance(strategy=InheritanceType.JOINED)
 public abstract class Payment
      @Id     @Column(name=”payment_id”)
      @GeneratedValue(strategy=GenerationType.AUTO)
      private int id = 0;
 }
 @Entity @Table(name=”check_payment”)
 @PrimaryKeyJoinColumn(name=”payment_id”)
 public class CheckPayment extends Payment{    
      private int check;
 }
 @Entity @Table(name=”credit_card_payment”)
 @PrimaryKeyJoinColumn(name=”payment_id”)
 public class CreditCardPayment extends Payment{    
      @Column(nullable=false)
      private String account;
 }
 create table payment { payment_id INTEGER, amount INTEGER, primary key(payment_id));
 create table check_payment { payment_id INTEGER, check-numer INTEGER, primary key(payment_id));
 create table credit_card_payment { payment_id INTEGER, account INTEGER, primary key(payment_id));
 
      Table por classe concreta
 •     Cada classe na hierarquia tem a sua própria tabela.
 •     O campos da classe pai são duplicadas em cada tabela.
 •     Duas abordagens:
 o     Subclass Union.
      Mapeia a classe pai normalmente, sem discriminador.
      @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
      Papeia cada uma das subclasses
 •     Especifica o nome da tabela
 •     Especifica as propriedades das subclasses
 o     Polimorfismo Implícito
      Class pai não é mapeada usando hibernate (@MappedSuperclass)
      Cada subclasse é mapeada como uma clase normal.
 •     Mapeia todas as propriedades, inclusive as propriedades do pai.
 @MappedSuperclass
 public class Vehicle{               //Class não é mapeada, mas as propriedades são.
      @Id      @Column(name=”vehicle_id”)
      @GeneratedValue(strategy=GenerationType.AUTO)
      private int id;
 }
 @Entity
 public class Car extends Vehicle{
      boolean coupe;
 }
 @Entity
 public class Truck extends Vehicle {
      @Column (name=”Max_weight”)
      private int maxWeight;
 }
 public SUV extends Truck {
      @Column (name=”spinner_wheels”)
      private boolean spinnerWheels;
 }
 create table vehicle ( vehicle_id INTEGER, coupe_ind bit, primary key(vehicle_id));
 create table truck ( vehicle_id INTEGER, max_weight bit, primary key(vehicle_id));
 create table suv ( vehicle_id INTEGER, max_weight bit, primary key(vehicle_id));
 
 
 Sem EJB
 EntityManagerFactory emf = Persistence.createEntityManagerFactory(“myapp);//O que está no persistence-unit
 EntityManager em = emf.createEntityManager();
 EntityTransaction et = em.getTransaction();
 et.begin();
      Insert: em.persist(carro);
      Update: em.merge(carro);
      Remove: em.remove(carro);
      Busca: Carro carro = em.find(Carro.class, id);
 et.commit() ou et.roolback();
 
 Com EJB
 EntityManagerFactory emf = Persistence.createEntityManagerFactory(“myapp);//O que está no persistence-unit
 @PersistenceContext
 EntityManager em = emf.createEntityManager();
 EntityTransaction et = em.getTransaction();
 et.begin();
      Insert: em.persist(carro);
      Update: em.merge(carro);
      Remove: em.remove(carro);
      Busca: Carro carro = em.find(Carro.class, id);
 et.commit() ou et.roolback();
 
  6.4.9.1 Entity Manager
 
 •     No Hibernate
 o     Configuration -> SessionFactoryy -> Session
 o     Session é o gateway para as funções de persistência.
 •     JPA
 o     Persistence -> EntityManagerFactory -> EntityManager
 o     EntityManager é o gateway para as funções de persistência.
 
 Ciclo de Vida de um Objeto
 Um objeto(Entity) pode ter 4 estados que indicam como eles estão conectados ao BD.
 •     New(transient): Objeto foi criado, mas ainda não foi persistido ou associado ao BD. Ao ser salvo com o EntityManager.persist() ele passa ao estado Managed.
 •     Managed(Persistent): O objeto já está associado ao BD. Mudanças no objeto vão, potencialmente gerar mudança no BD. Se necessário pode-se chamar EntityManager.flush() para sincronizar as mudanças, senão somente no commit da transação.
 •     Detached: O objeto já foi associado ao BD, mas não está mais. Um objeto Detached pode ser reatached usando o EntityManager.merge().
 •     Removed: Objeto que recebeu a operação de remoção. EntityManager.remove();
 
 Similar ao Hibernate Session, controla o ciclo de vida das entidades.
 •     new() → Cria uma nova entidade
 •     persist() → Salva ou faz um update em uma entidade
      public Order createNewOrder(Customer customer){
           Order order = new Order(customer);
           entityManager.persist(order);
           return order;          }
 •     refresh() → Atualiza o estado da entidade
 •     remove() → Marca uma entidade para remoção
      public void removeOrder(Long orderId){
           Order order = entityManager.find(Order.class, orderId);
           entityManager.remove(order);      }
 •     merge() → Sincroniza o estado de entidades desacopladas.
      public void updateOrder(Order order){
           entityManager.merge(order);      }
 •     find(Class type, Serializeble id) – Obtém o item de um tipo pelo id
 •     getTransaction
 ◦     Prove um objeto de transação para fazer o commit e rollback.
 
 

Nenhum comentário:

Postar um comentário