Introdução ao Hibernate e mapeamento objeto-relacional
1. Hibernate
O Hibernate é um framework para o mapeamento objeto-relacional escrito na
linguagem Java, mas também é disponível em .Net como o nome NHibernate. Este
programa facilita o mapeamento dos atributos entre uma base tradicional de dados
relacionais e o modelo objeto de uma aplicação, mediante o uso de arquivos (XML)
para estabelecer esta relação. Hibernate é um software livre de código aberto distribuído
com a licença LGPL.
Características
O objetivo do Hibernate é diminuir a complexidade entre os programas Java,
baseado no modelo orientado a objeto, que precisam trabalhar com um banco de dados
do modelo relacional (presente na maioria dos SGDBs). Em especial, no
desenvolvimento de consultas e atualizações dos dados. Sua principal característica é a
transformação das classes em Java para tabelas de dados (e dos tipos de dados Java para
os da SQL). O Hibernate gera as chamadas SQL e libera o desenvolvedor do trabalho
manual da conversão dos dados resultante, mantendo o programa portável para
quaisquer bancos de dados SQL, porém causando um pequeno aumento no tempo de
execução. Nas questões relacionadas para o gerenciamento de transações e na
tecnologia de acesso à base de dados são de responsabilidade de outros elementos na
infraestrutura do programa. Apesar de existirem API no Hibernate para possuir
operações de controle transacional, ele simplesmente delegará estas funções para a
infraestrutura na qual foi instalada. No caso de aplicações construídas para serem
executadas em servidores de aplicação, o gerenciamento das transações é realizado
segundo o padrão JTA. Já nas aplicações standalone, o programa delega o tratamento
transacional ao driver JDBC. Hibernate pode ser utilizado em aplicações Java
standalone ou em aplicações Java EE, utilizando servlet ou sessões EJB beans.
História
Hibernate foi criado por desenvolvedores Java, espalhados ao redor do mundo, e
liderado por Gavin King. Posteriormente, JBoss Inc (empresa comprada pela Red Hat)
contratou os principais desenvolvedores do programa para fazer o seu suporte. A atual
versão do Hibernate é a 3.x, que incorporou características como a nova arquitetura
Interceptor/Callback, filtros definidos pelo usuário e anotações JDK 5.0 (Metadados do
Java), que substitui os arquivos XML. Hibernate 3 também se aproxima das
especificações EJB 3.0 e atua como a espinha dorsal das implementações EJB 3.0 em
JBoss.
HQL
A HQL (Hibernate Query Language) é um dialeto SQL para o Hibernate. Ela é
uma poderosa linguagem de consulta que se parece muito com a SQL, mas a HQL é
totalmente orientada a objeto, incluindo os paradigmas de herança, polimorfismo e
encapsulamento. No Hibernate, você pode escolher tanto usar a SQL quanto a HQL.
Escolhendo a HQL, você poderá executar os pedidos SQL sobre as classes de
persistência do Java ao invés de tabelas no banco de dados, aumentando, assim, a
distância entre o desenvolvimento da regras de negócio e o banco de dados.
2. Persistência usando Hibernate
Introdução
• Hibernate é um Framewok para mapeamento Objeto/Relacional em Java
• Possibilita desenvolver classes persistentes usando Java convencional:
o Associação
o Composição
o Herança
o Polimorfismo
o e coleções Java
• Implementa mecanismos de mapeamento:
o Classes Java <-> Tabelas em SGBDs relacionais
o Tipos Java <->Tipos SQL
• Implementa mecanismos convenientes para consulta e recuperação de dados
• Hibernate objetiva reduzir em cerca de 95% do tempo de desenvolvimento de
tarefas relacionadas à persistência!
Visão Geral
• A figura abaixo é uma descrição de alto nível da arquitetura do Hibernate
• O Hibernate persiste objetos java comuns (POJO)
• Usa reflexão para acessar as propriedades persistentes de um objeto
• As classes persistentes são definidades (descritas) em documentos de
mapeamento
o Arquivos XML são usados para descrever os campos, associações e
subclasses persistentes
3. o Os Mapeamentos são "compilados" na inicialização da aplicação
o Podem ser usados também para operações de suporte como:
Geração de esquemas do banco de dados
Geração de código-fonte Java
Código típico no uso do Hibernate:
...
SessionFactory sf = new
Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Cliente cliente = new Cliente();
cliente.setNome("Maria");
cliente.setEndereco("Endereço de Maria");
cliente.setEmail("maria@xpto.com");
session.save(cliente);
tx.commit();
session.close();
...
• O código destacado está relacionado à operação do Hibernate
o O primeiro passo da aplicação é obter uma Session
Esta é a principal interface entre a aplicação e o Hibernate
A SessionFactory permite a aplicação criar sessões a partir de
arquivos de configuração hibernate.cfg.xml
o Após definir questões transacionais (opcional) a aplicação pode usar
objetos persistentes e a sessão hibernate para salvar dados no SGBD.
Iniciando uso do Hibernate
• O Hibernate funciona bem com o modelo POJO
• O uso de tipos de propriedades não é restrito
o É permitido qualquer tipo Java (incluindo coleções)
o É possível mapear valores, coleções de valores e associações com outros
objetos
• A classe persistente não precisa implementar/herdar qualquer classe especial do
framework
4. Exemplo:
import java.io.Serializable;
import java.util.Date;
public class Cliente implements Serializable {
private Long id;
private String nome;
private String endereco;
private String email;
private Date nascimento;
public Cliente(){
}
public void setId(Long id){
this.id = id;
}
public Long getId(){
return id;
}
public void setNome(String nome){
this.nome = nome;
}
public String getNome(){
return nome;
}
...
public void setNascimento(Date nascimento){
this.nascimento = nascimento;
}
public Date getNascimento(){
return nascimento;
}
}
• A classe Cliente precisa de um mapeamento para se tornar persistente
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "
-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
5. <class name="Cliente" table="CLIENTE">
<id column="CLIENTE_ID" name="id"
type="java.lang.Long">
<generator class="sequence"/>
</id>
<property
column="NOME"
length="50"
name="nome"
not-null="true"
type="java.lang.String"
/>
...
<property
column="DATRA_NASCIMENTO"
name="nascimento"
type="java.util.Date"
/>
</class>
</hibernate-mapping>
• Os documentos de mapeamento podem ser gerados automaticamente a partir da
base de dados ou das classes java
• O elemento <class> mapeia uma classe a uma tabela
• O elemento <id> um atributo da classe à chave-primária da tabela
• O elemento <property> mapeia os demais atributos do objeto às colunas da
tabela
• Por fim, é necessário criar o arquivo de configuração do hibernate:
<!DOCTYPE hibernate-configuration PUBLIC"
-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="hibernate.dialect">org.hibernate.dialect.MySQLMyISAMDialect</pro
perty>
6. <property
name="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</prop
erty>
<property
name="hibernate.connection.url">jdbc:mysql://localhost:3306/exemplo</p
roperty>
<property
name="hibernate.connection.username">root</property>
<property
name="hibernate.connection.password">r00Tp@$wd</property>
<mapping-resource="Cliente.hbm.xml"/>
</session-factory>
</hibernate-configuration>
• O arquivo de configuração provê informações ao framework para conectar-se ao
banco de dados
• O elemento <mapping-resource> aponta para o arquivo de mapeamento
Mais sobre mapeamento:
Mapeamento de Associações
• Para mapear relações entre objetos persistentes usa-se os elementos <many-to-
one> e <one-to-one>
o Mapeamento muitos-para-um com Cliente -> Dependentes
<many-to-one name="cliente"
column="CLIENTE_ID"
class="Cliente"
not-null="true"/>
o Mapeamento um-para-um com Cliente -> Usuário
<one-to-one name="usuario" class="Usuario"/>
Mapeamento de Coleções
• Hibernate persiste as seguintes coleções
o java.util.Map
o java.util.Set
o java.util.SortedMap
o java.util.SortedSet
o java.util.List
o e qualquer Array de objetos (ou valores) persistentes
• Propriedades do tipo java.util.Collection e java.util.List podem ser persistidos
como "bag"
• Coleções são mapeadas usando os elementos <set>, <list>, <map>, <bag>,
<array> e <primitive-array>
• Uma tabela para a coleção é requerida quando ela contem valores ou referencias
para outras entidades mapeadas em muitos-para-muitos
o Segue um exemplo de mapeamento para uma coleção de String
7. <set name="enderecos" table="ENDERECOS">
<key column="CLIENTE_ID"/>
<element column="endereco" type="string"/>
</set>
o O elemento <key> indica a chave estrangeira na tabela ENDERECOS
• Para relacionamentos um-para-muitos as tabelas das classes são ligadas
diretamente (sem uso de tableas intermediárias)
o Exemplo:
<set name="dependentes" inverse="true">
<key column="CLIENTE_ID"/>
<one-to-many class="Dependente" />
</set>
o Este é o mapeamento da coleção de dependentes de um Cliente
o o atributo inverse indica que Dependente também referencia Cliente
<many-to-one name="cliente"
column="CLIENTE_ID"
class="Cliente"
not-null="true"
/>
o Em dependente é declarada a existência da relação.
• Outras questões importantes:
o Lazy Initialization
o Relacionamentos ternários
Mapeamento de Herança
• O Hibernate suporta três estratégias de mapeamento de herança
o Uma tabela por hierarquia de classes
o Uma tabela por subclasse
o Uma tabela por classe concreta (polimorfismo implícito)
• Não é possível misturar as estratégias para um mesmo mapeamento de classe
• Suponha que tenhamos a classe Pessoa e as subclasses Cliente, Fornecedor e
Funcionario
<class name="Pessoa" table="PESSOA">
<id name="id" type="long" column="PESSOA_ID">
<generator class="native"/>
</id>
<discriminator column="TIPO_PESSOA" type="string"/>
<property name="nome" column="NOME"/>
...
<subclass name="Cliente" discriminator-value="CLT">
...
</subclass>
<subclass name="Funcionario" discriminator-value="FCN">
...
</subclass>
<subclass name="Fornecedor" discriminator-value="FRC">
...
8. </subclass>
</class>
• No código acima temos a estratégia de uma tabela por hierarquia
• Apenas uma tabela é necessária, com todos os atributos da classe e suas
subclasses
• A coluna <discriminator> indicará qual classe uma tupla representa
• A grande limitação é que colunas das subclasses não podem ser declaradas
NOT-NULL
<class name="Pessoa" table="PESSOA">
<id name="id" type="long" column="PESSOA_ID">
<generator class="native"/>
</id>
<property name="nome" column="NOME"/>
...
<joined-subclass name="Cliente" table="CLIENTE">
<key column="PESSOA_ID"/>
...
</joined-subclass>
<joined-subclass name="Funcionario" table="FUCNIONARIO">
<key column="PESSOA_ID"/>
...
</joined-subclass>
<joined-subclass name="Fornecedor" table="FORNECEDOR">
<key column="PESSOA_ID"/>
...
</joined-subclass>
</class>
• No código acima temos a estratégia de uma tabela por subclasse
• Quatro tabelas serão usadas, uma para a superclasse e três para as subclasses
• As tabelas das subclasses estão ligadas à da superclasses via chave-estrangeira
• Melhor estratégia do ponto de vista relacional
<class name="Cliente" table="CLIENTE">
<id name="id" type="long" column="CLIENTE_ID">
<generator class="native"/>
</id>
<property name="nome" column="NOME"/>
...
</class>
<class name="Funcionario" table="FUNCIONARIO">
<id name="id" type="long" column="FUNCIONARIO_ID">
<generator class="native"/>
</id>
<property name="nome" column="NOME"/>
...
</class>
<class name="Fornecedor" table="FORNECEDOR">
<id name="id" type="long" column="FORNECEDOR_ID">
<generator class="native"/>
</id>
<property name="nome" column="NOME"/>
...
</class>
• No código acima temos a estratégia de uma tabela por classe concreta
9. • Note que a superclasse Pessoa não foi explicitamente mencionada
• Usa três tabelas, cada uma replicando os atributos de pessoa
• Para indicar o polimorfismo usa-se o elemento <any>
<any name="pessoa"
meta-type="class"
id-type="long">
<column name="PESSOA_CLASS"/>
<column name="PESSOA_ID"/>
</any>
Consultas
• As consultas usando Hibernate podem ser feitas de três formas
o Usando HQL (Hibernate Query Language)
o Usando Criteria Queries
o Usando SQL Nativo
Consultas HQL
• O HQL é uma linguagem SQL like, porém, "orientada a objetos"
• Possibilita descrever consultas polimórficas
• Possibilita consultas sobre coleções
from Pessoa pessoa where upper(pessoa.nome) like 'MARIA%'
• A consulta acima retorna todos os objetos da classe pessoa e de suas subclasses
que tenham o nome começado por MARIA
• Possibilita descrever consultas polimórficas
• Possibilita consultas sobre coleções
Query q = session.createQuery("from Pessoa pessoa where
upper(pessoa.nome) like :NOME");
q.setProperties(nome);
List pessoas = q.list();
Criteria Queries
• É uma API (bastante intuitiva) extendível para executar consultas
• Para executá-la, basta criar um objeto Criteria e definir nele os critérios da
consulta
Criteria consulta = sess.createCriteria(Pessoa.class);
consulta.add( Expression.like("nome", "Maria%") );
consulta.add( Expression.between("idade", 18, 40) );
List resultado = consulta.list();
• A consulta acima vai retornar todas as Marias com idade entre 18 e 40 anos
Considerações
• O Hibernate é um framework consolidado para fazer persistência
10. o Separa bem as coisas (o mundo OR do mundo OO)
o O overhead é extremamente satisfatório
o É mantido por uma comunidade muito ativa
• O maior esforço para usá-lo está na construção e manutenção dos mapeamentos
• Existem muitas ferramentas de apoio ao desenvolvimento usando Hibernate
o XDoclets
o Plugins para o Eclipse
o Uso adequado destas ferramentas deixa apenas o trabalho estritamente
necessário para o desenvolvedor
Recursos
• Página Principal: http://www.hibernate.org
• Documentação Oficial (em inglês):
http://www.hibernate.org/hib_docs/reference/en/html/
• Mapeamentos:
http://www.j2eebrasil.com.br/jsp/tutoriais/tutorial.jsp?idTutorial=003_007
• Coleções:
http://www.j2eebrasil.com.br/jsp/tutoriais/tutorial.jsp?idTutorial=003_006
• IDs:
http://www.allapplabs.com/hibernate/hibernate_o_r_mapping_generator_elemen
t.htm
• Apostila bacana:
http://www.guj.com.br/content/articles/hibernate/intruducao_hibernate3_guj.pdf
• POJO: http://en.wikipedia.org/wiki/Plain_Old_Java_Object