1 hibernate introdução caio nakashima [email protected] [email protected]
TRANSCRIPT
2
Primeira Aplicação
• Será criada uma aplicação simples baseado no console do Hibernate.
• O banco de dados neste exemplo poderá armazenar eventos que se deseja atender e informações sobre o anfitrião destes eventos.
• O primeiro passo é configurar a pasta de desenvolvimento e colocar todas as bibliotecas Java necessárias nele.
• Abaixar a distribuição do Hibernate do site http://www.hibernate.org ou da pasta do servidor.
3
Bibliotecas necessárias
• +lib– antlr.jar– cglib-full.jar– asm.jar– asm-attrs.jars– commons-collections.jar– commons-logging.jar– ehcache.jar– hibernate3.jar– jta.jar– dom4j.jar– log4j.jar
4
Bibliotecas necessárias
• Extrair o pacote e colocar todas as bibliotecas necessárias que se encontram em /lib para a pasta /lib da pasta de desenvolvimento.
• A lista da transparência anterior é o conjunto mínimo das bibliotecas necessárias.
• É interessante consultar o arquivo README.txt da pasta /lib da distribuição do Hibernate para maiores informações sobre as bibliotecas adicionais de terceiros.
5
Classe
• Será criada uma classe que representa um evento que se deseja armazenar no banco de dados.
• A classe deste exemplo é uma classe JavaBean com algumas propriedades.
• Observe que a classe utiliza o padrão de nomes do JavaBean para as propriedades dos métodos get e set, assim como a visibilidade dos campos privados.
• Esta é uma recomendação de projeto, mas não é obrigatório.
• Hibernate pode acessar campos diretamente, o benefício de métodos de acesso é a robustez para refactoring.
6
import java.util.Date;public class Event { private Long id; private String title; private Date date; Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }}
Event.java
7
Identificadores
• A propriedade ID carrega o valor do identificador único para um evento particular.
• Todas as classes de persistência de entidades necessitam de uma propriedade identificadora para utilizar o conjunto completo das características do Hibernate.
• Em geral não se manipula o identificador de um objeto, então o método set deve ser privado. – Somente o Hibernate pode atribuir valores aos identificadores quando
um objeto é salvo.
• Observa-se que o Hibernate pode acessar métodos de acesso public, private e protected assim como os campos diretamente.
8
import java.util.Date;public class Event { private Long id; private String title; private Date date; Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }}
Event.java
Identificadores, definição das interfaces
9
Construtor
• É necessário um construtor sem argumentos para todas as classes de persistência.– Hibernate tem que criar uma classe utilizando Java
Reflection.
• O construtor pode ser privado, porém a visibilidade do pacote (package) é requerida pelo runtime proxy generation e uma recuperação de dados eficiente sem a instrumentação de bytecode.
• Para o exemplo colocar a fonte Java em uma pasta denominada /src na pasta de desenvolvimento.
+lib
<Hibernate and third-party libraries>
+src
Event.java
10
import java.util.Date;public class Event { private Long id; private String title; private Date date; Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }}
Event.java
Construtores
11
Arquivo de mapeamento
• É necessário especificar para o Hibernate como carregar e armazenar objeto da classe de persistência.
• O arquivo de mapeamento faz este papel– Especifica qual tabela do banco de dados deve ser
acessado– Quais colunas da tabela devem ser utilizadas.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
[...]
</hibernate-mapping>
12
Arquivo DTD
• Pode-se utilizar o arquivo DTD do Hibernate para a auto complementação dos elementos de mapeamento XML e atributos em um editor de programas ou IDE.
• Sugere-se abrir o arquivo DTD para verificar todos os elementos, atributos e valores padrão.
• Hibernate não carregará o arquivo DTD da internet, mas primeiro procura-o no classpath da aplicação.– Esta localizado em .\src\org\hibernate
13
hibernate-mapping
• Entre duas tags hibernate de mapeamento, incluir uma classe de elemento.
• Todas as classes de persistência de entidade necessitam um mapeamento para uma tabela em uma tabela do banco de dados SQL.
• Abaixo definiu-se como persistir e carregar objetos da classe Event para a tabela EVENTS, cada instância representada por uma linha desta tabela.
<hibernate-mapping> <class name="Event" table="EVENTS"> </class></hibernate-mapping>
14
Identificador único de entidade
• Para mapear o identificador único para a chave primária da tabela, é necessário configurar a estratégia de geração dos valores para serem colocadas na coluna da chave primária.
<hibernate-mapping> <class name="Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="increment"/> </id> </class></hibernate-mapping>
15
Chave primária• O elemento ID é a declaração da propriedade do
identificador.– name="id"
• declara o name da propriedade Java-Hibernate que será utilizada para métodos SET e GET para acessar dos dados.
• O atributo column faz a ligação para o Hibernate qual coluna da tabela EVENTS será utilizado como chave primária.– column="EVENT_ID"
• O elemento generator especifica qual estratégia para gerador de dados.– Neste exemplo está sendo utilizado o método de incremento in-
memory, muito útil para teste.
• Hibernate também suporta geração de valor automáticos pelo banco de dados, assim como identificadores atribuídos pela aplicação.
16
Propriedades de persistência
• Por padrão nenhuma propriedade da classe é considerada para persistência.
• O nome do atributo da propriedade do elemento indica para o Hibernate qual método get e set deve ser utilizado.
• Por que a propriedade de mapeamento data incluir o atributo da coluna e a propriedade title não?
• Sem o atributo coluna Hibernate por padrão utiliza a propriedade nome como o nome da coluna.
• Date é uma palavra reservada na maioria dos banco de dados, assim é melhor mapear com um nome diferente.
17
Event.hbm.xml
<hibernate-mapping>
<class name="Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="increment"/>
</id>
<property name="date" type="timestamp"
column="EVENT_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>
18
Forma de mapeamento• Por que o atributo title não tem definido seu tipo?
– Os tipos declarados e utilizados no arquivo de mapeamento não são tipos de dados Java.
– Também não são tipos de dados SQL.
• São tipos denominados Tipos de Dados de Mapeamento Hibernate.– Ele converte tipos de dados Java para tipos de dados SQL e vice
versa.
• Hibernate tenta determinar a conversão correta e mapear tipos de atributos que não estão presentes no arquivo de mapeamento.
• Em alguns casos detecção automática de tipo de dados, utilizando Reflection on Java Class, pode não ter um valor padrão conforme esperado.– Este é o caso da propriedade date.– Hibernate não sabe se a propriedade deve ser mapeada para o tipo
DATE ou TIMESTAMP ou TIME do SQL.
19
Event.hbm.xml
• O arquivo de mapeamento deve ser salvo com o nome Event.hbm.xml, na pasta onde está armazenado a fonte do Event.java.
• O nome do arquivo pode ser de livre escolha, mas o sufixo deve ser hbm.xml.
• A estrutura de diretório deve ser:
+lib
<Hibernate and third-party libraries>
+src
Event.java
Event.hbm.xml
20
Exercício
• Criar um arquivo denominado Event.hbm.xml o mapeamento do arquivo. (Pasta src)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="increment"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>
21
Configurando para acessar Postgresql
• Buscar no site do PostgreSql (http://jdbc.postgresql.org/download.html/) os drivers JDBC.
• Colocar na pasta lib o arquivo • Criar na raiz da pasta de desenvolvimento uma
pasta denominada data.+lib
<Hibernate and third-party libraries>
postgresql-8.1-404.jdbc2.jar
+src
Event.java
Event.hbm.xml
+data
22
Conexão com o banco de dados
• Hibernate é a camada da aplicação que conecta-se com o banco de dados, assim ele necessita de informações sobre a conexão.
• As conexões são efetivadas através de um grupo de conexões JDBC (JDBC connection pool) que deve ser configurado também.
• A distribuição Hibernate contém inúmeras ferramentas de conexões JDBC de código aberto (open source JDBC connection).
• Para a configuração do Hibernate pode utilizar o arquivo hibernate.properties ou hibernate.cfg.xml ou via aplicação.
23
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">
org.postgresql.Driver
</property>
<property name="connection.url">
jdbc:postgresql://localhost:5432/postgres
</property>
<property name="connection.username">postgres</property>
<property name="connection.password">1234</property>
24
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">
org.hibernate.dialect.PostgreSQLDialect
</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="Event.hbm.xml"/>
</session-factory>
</hibernate-configuration>
25
<session-factory>
• Este arquivo de configuração XML utiliza um arquivo DTD diferente.
• Configura-se Hibernate's SessionFactory uma fábrica responsável por um banco de dados particular.
• Se existirem mais de um banco de dados, utiliza-se inúmeras configurações <session-factory> geralmente um arquivo para cada configuração para facilitar a sua inicialização.
26
JDBC
• Os primeiros 4 elementos (propriedades) contém as informações necessárias para a conexão JDBC.
<property name="connection.driver_class">
org.postgresql.Driver
</property>
<property name="connection.url">
jdbc:postgresql://localhost:5432/postgres
</property>
<property name="connection.username">postgres</property>
<property name="connection.password">1234</property>
27
Dialeto• Propriedade do elemento dialeto especifica uma variante
SQL particular gerado pelo Hibernate
• A opção hbm2ddl.auto habilita a geração automática dos esquemas de banco de dados (database schemas) diretamente dentro de banco de dados.• Removendo-se esta opção de configuração pode-se
desligar esta característica. • Pode-se redirecionar para um arquivo com a ajuda do
SchemaExport (ANT)
<property name="dialect"> org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hbm2ddl.auto">create</property>
28
Event Mapping• Adiciona-se o(s) arquivo(s) de mapeamento para as classes
de persistência. <mapping resource="Event.hbm.xml"/>
.
• Copia-se este arquivo para o diretório fonte, assim completa o classpath.
• Hibernate automaticamente procura por um arquivo denominado hibernate.cfg.xml na raiz do classpath durante a inicialização.
• Criar o arquivo de configuração do Hibernate (hibernate.cfg.xml).
+lib <Hibernate and third-party libraries>+src Event.java Event.hbm.xml hibernate.cfg.xml
29
Inicialização
• Na inicialização deve incluir a construção de um objeto SessionFactory para armazena-lo em algum lugar para fácil acesso pelo código da aplicação.
• Uma SessionFactory pode abrir uma nova seção.• Uma seção representa uma unidade de trabalho thread
simples (single thread), a SessionFactory é um objeto global de uma thread segura, instanciada uma única vez.
• Será criada uma classe de ajuda HibernateUtil que cuidará da inicialização e fará com que a manipulação da seção seja conveniente.
• Assim o padrão de seção ThreadLocal chamado é útil aqui, para manter a unidade de trabalho corrente com a thread corrente.
30
SessionFactory
• Esta classe além de produzir uma seção global do SessionFactory em sua inicialização estática (chamada uma única vez pelo JVM quando a classe é carregada), mas também tem uma variável ThreadLocal para armazenar a seção da thread corrente.
• Sempre que for chamado o método HibernateUtil.currentSession() retornará sempre a mesma unidade de trabalho Hibernate em um mesmo thread.
• Uma chamda para o método HibernateUtil.closeSession() finaliza a unidade de trabalho corrente associada com um thread.
31
Nota: HibernateUtil• Esta classe não é necessária se for implementar o
Hibernate em um servidor de aplicações J2EE:– Um seção será automaticamente limitado pela transação
corrente JTA e pode-se procurar a SessionFactory através do JNDI.
• Se utilizar o servidor de aplicação JBoss, pode se implementado como um serviço de gerenciamento de sistema e será automaticamente associada a SessionFactory para uma nome JNDI.build.xml+lib <Hibernate and third-party libraries>+src Event.java Event.hbm.xml HibernateUtil.java hibernate.cfg.xml+data
32
Registro de Ocorrências
• Agora é necessário configurar o sistema de registro de ocorrências (logging system).
• Hibernate utiliza commons logging e permite escolher entre Log4j e JDK 1.4 logging.
• A maioria dos desenvolvedores preferem Log4j.– Copiar o arquivo log4j.properties para a pasta /src na
mesma pasta do hibernate.cfg.xml.
• A saída padrão das mensagens de inicialização são apresentadas em stout.
33
Armazenado e Carregando Objetosimport org.hibernate.Transaction;import org.hibernate.Session;import java.util.Date;public class EventManager { public static void main(String[] args) { EventManager mgr = new EventManager(); if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } HibernateUtil.sessionFactory.close(); } private void createAndStoreEvent(String title, Date theDate){ Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); tx.commit(); HibernateUtil.closeSession(); }}
34
• Cria-se um novo objeto Event, que manipula o Hibernate.• Hibernate cuida do SQL e executa as inserções no banco de
dados.• Uma seção é uma simples unidade de trabalho.• Uma unidade de trabalho pode ser mais longa que uma
simples transação no banco de dados.– Exemplo: uma unidade de trabalho que faz inúmeras chamadas http
request/response em uma aplicação web.
• Separar a transação com o banco de dados da unidade de trabalho e com a aplicação do ponto de vista do usuário é um dos conceitos básicos de projeto do Hibernate.
35
Application Transaction• Pode-de denominar uma unidade de trabalho longa que
geralmente encapsula inúmeras transações pequenas de banco de dados como Application Transaction.
• O API de Transação Hibernate, é opcional, mas é utilizado por sua portabilidade e conveniência.
• Para manipular a transação do banco dados, chamando o método session.connection.commit(), deve-se atribuir um código específico para o ambiente de desenvolvimento.
• Por padrão de configuração do Hibernate pode-se implantar a camada de persistência em qualquer banco de dados.
• No capítulo 12 do Hibernate Reference Documentation pode-se obter mais informações sobre o assunto.
36
Netbeans Eclipse
Lib localizado em minLib do Hibernate – Postgresql
NetBeans
37
Eclipse
Lib localizado em minLib do Hibernate – Postgresql
38
Para adicionar eventos
• Para armazenar eventos, pode-se adicionar uma opção no método main:
sf = new Configuration().configure().buildSessionFactory();Session session = sf.openSession(); //Abre sessaoTransaction tx = session.beginTransaction(); //Cria transacao
//Cria objeto EventoEvent theEvent = new Event();theEvent.setTitle("Evento Novo");theEvent.setDate(new Date());session.save(theEvent);tx.commit(); //Fecha transacaosession.close(); //Fecha sessao
13:45:09,734 DEBUG SchemaExport:301 - drop table EVENTS_POSJAVA13:45:09,890 DEBUG SchemaExport:301 - drop sequence hibernate_sequence13:45:09,906 DEBUG SchemaExport:301 - create table EVENTS_POSJAVA (EVENT_ID int8 not null, EVENT_DATE timestamp, title varchar(255), primary key (EVENT_ID))13:45:10,171 DEBUG SchemaExport:301 - create sequence hibernate_sequence13:45:10,187 INFO SchemaExport:194 - schema export completeHibernate: select nextval ('hibernate_sequence')Hibernate: insert into EVENTS_POSJAVA (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)
39
listEvents() sf = new Configuration().configure().buildSessionFactory(); Session session = sf.openSession(); //Abre sessao List listaEventos = session.createQuery("from Event").list(); for (int i = 0; i < listaEventos.size(); i++) { Event theEvent = (Event) listaEventos.get(i); System.out.println(" Id:"+theEvent.getId()); System.out.println(" Titulo:"+theEvent.getTitle()); System.out.println(" Data: "+ theEvent.getDate()); } session.close(); //Fecha sessao
• É utilizado aqui HQL (Hibernate Query Language) para consultar e carregar todos os objetos de Eventos existentes do banco de dados.
• Hibernate gerará a expressão SQL apropriada e enviará para o banco de dados e populará os objetos Events com os dados.
40
Exercício• Desenvolver um código para criar, inserir e listar os dados da
tabela abaixo:– A) PostgreSQL– B) MySQL
• Analise o exemplo Estado, que lista os dados da tabela estado.• Elabore um exemplo para listar o Municípios.
Pessoa
Pessoa_ID (PK)NomeSexoData_nascimento