Hibernate
Java avançado – PCC
Jobson Ronan {[email protected]}
Guilherme Kelly {[email protected]}
O que é?

Hibernate é uma moderna solução de
mapeamento objeto-realcional(ORM)
Persistência tranparente (POJO/Java
Beans)
 “Lazy Fetching”
 Uso de uma Cache
 Três estratégias para o mapeamento de
heranças

O que é?
Pra que transparência?




Persistência sem impacto no código dos
objetos de negócio
Qualquer classe pode ser uma classe
persistente sem ser necessário
implementar nenhuma classe ou interface
Classes persistentes podem ser usadas
fora do contexto de persistência (ex
Testes)
Total portabilidade sem dependências
Problemas dos BDRs

Modelagem
Não há polimorfismo
 Não há herança


Lógica de negócio

Stored procedures -> perca de
portabilidade
Vantagens dos RDBs

Trabalhar com grandes quantidades de
dados


Trabalhar com conjuntos de dados


Junções e agregações
Compartilhamento



Busca, ordenação
Concorrência (Transações)
Muitas aplicações
Integridade


Restrições (Constraints)
Isolação de transações

Obviamente, ainda precisamos dos
RDBs
Objetivo


Aproveitar-se das vantagens
oferecidas pelos RDBs
Isso sem perder a orientação a
objetos
Objetivo Real
Ter menos trabalho 
 Ter um DBA feliz 

Em prática

Locadora em partes...
Em prática

Classe Persistente



Construtor default
Pares de Get´s e
Set´s
Uma propriedade
identificadora
package br.org.citi.pec.locadora;
public class Filme {
private int codigo;
private String nome;
public int getCodigo() {
return codigo;
}
private void setCodigo(int codigo) {
this.codigo = codigo;
}
public String getNome() {
return nome;
}
private void setNome(int nome) {
this.nome = nome;
}
}
Em prática

Mapeamento XML
Metadado legível
 Mapeamento de tabelas e colunas

<?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="br.org.citi.pec.locadora.Filme" table="filmes">
<id name="codigo" column="filme_id">
<generator class="native" />
</id>
<property name="nome" column="nome"/>
</class>
</hibernate-mapping>
Em prática

Salvando um objeto
Session session = sessionFactory.openSession();
Transaction tx = s.beginTransaction();
Filme filme = new Filme();
filme.setNome(novoNome);
session.save(filme);
tx.commit();
session.close();
Também pode ser usado saveOrUpdate
Em prática

Carregando um objeto
Session session = sessionFactory.openSession();
Filme filme =
(Filme) session.load(Filme.class,
new Integer(filmeId);
session.close();


Não use load para determinar se um objeto
existe (uma exceção é lançada neste caso)
Use get. Este retorna null caso o objeto não
exista
Em prática

Removendo um objeto
Session session = sessionFactory.openSession();
Transaction tx = s.beginTransaction();
Filme filme =
(Filme) session.get(Filme.class,
new Integer(filmeId);
session.delete(filme);
tx.commit();
session.close();
Em prática

Atualizando um objeto (Dirty Checking)

Obetendo um filme e alterando seu nome
Session session = sessionFactory.openSession();
Transaction tx = s.beginTransaction();
Filme filme =
(Filme) session.get(Filme.class,
new Integer(filmeId);
filme.setNome(novoNome);
tx.commit();
session.close();
Não é necessário uma chamada explicita do update
Estado dos Objetos

Alguns conceitos sobre objetos

Transiente.
• Nunca persistido. Não associado a nenhuma
sessão (Session)

Persistente
• Associado a uma única sessão

Desacoplado (Detached)
• Já persistido, mas não associado a nenhuma
sessão
Estado dos Objetos

Dirty Checking só funciona em
objetos persistentes

Use update para objetos desacoplados
Mais prática

Melhorando nosso modelo...
Mais prática

Classes persistentes
package br.org.citi.pec.locadora;
public class Cliente {
private String login;
private String CPF;
private String nome;
private Set locacoes = new Hashset();
//... Get´s e Set´s
}
Mais prática

Classes persistentes
package br.org.citi.pec.locadora;
public class Locacao {
private int id;
private Filme filme;
private Cliente cliente;
private Date dataLocacao;
private Date datadevolucao;
//... Get´s e Set´s
}
Mais prática

XML...
<?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="br.org.citi.pec.locadora.Cliente"
table="Clientes">
<id name="login"/>
<property name="nome" />
<property name="cpf" />
<set name="locacoes">
<key column="cliente_login" />
<one-to-many class="br.org.citi.pec.locadora.Locacao"/>
</set>
</class>
</hibernate-mapping>
Mais prática

XML...
<?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="br.org.citi.pec.locadora.Locacao"
table="Locacoes">
<id name="id">
<generator class="native" />
</id>
<property name="dataLocacao" />
<property name="dataDevolucao" />
<many-to-one
name="cliente" class="br.org.citi.pec.locadora.Cliente"
column="cliente_login"/>
<many-to-one
name="filme" class="br.org.citi.pec.locadora.Filme"
column="filme_id"/>
</class>
</hibernate-mapping>
Mais prática

Persistência transitiva
Locacao locacao = new Locacao();
Locacao.setDataLocacao(new Date());
Session session = sessionFactory.openSession();
Transaction tx = s.beginTransaction();
Filme filme = (Filme)
session.get(Filme.class, new Integer(filmeId);
Cliente cliente = (Cliente)
session.get(Cliente.class, login);
locacao.setCliente(cliente);
locacao.setFilme(filme);
cliente.getLocacoes().add(locacao);
tx.commit();
session.close();
Otimizando

Como as coleções são carregadas
Lazy fetching (Default)
 Eager (Outer Join) fetching

• Indicado nos XML, ou na própria consulta
Lazy fetching

SQL escondido:
Cliente cliente = (Cliente) session.get(Cliente.class, login);
SELECT … FROM CLIENTES C WHERE C.LOGIN = ?
Iterator cliente = cliente.getLocacoes().iterate();
SELECT … FROM LOCACOES L WHERE L.LOGIN_CLIENTE = ?
Filme filme = locacao.getFilme();
SELECT … FROM FILMES F WHERE F.FILME_ID = ?
Outer join fetching

SQL escondido:
Cliente cliente = (Cliente) session.get(Cliente.class, login);
SELECT … FROM CLIENTES C
LEFT OUTER JOIN LOCACOES L ON L.LOGIN_CLIENTE = C.LOGIN
LEFT OUTER JOIN FILME F ON L.FILME_ID = F.FILME_ID
WHERE C.LOGIN = ?
Herança

Estratégias para o mapeamento de
herança
Uma tabela por hierarquia de classes
 Uma tabela por subclasse
 Uma tabela por classe concreta

Herança

Uma tabela por subclasse
<?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="br.org.citi.pec.locadora.Cliente"
table="Clientes">
<id name="login" column="LOGIN" />
...
<joined-subclass
name="br.org.citi.pec.locadora.ClienteEspecial"
table="ClientesEspeciais">
<key column="LOGIN" />
<property ... />
...
</joined-subclass>
</class>
</hibernate-mapping>
Otimizando

Como otimizar?
Minimizando a leitura de linhas das
tabelas
 Minimizando a quantidade de comandos
SQLs enviados

Otimizando

Minimizando a leitura de linhas das
tabelas


Usar lazy fecthing
Minimizando a quantidade de
comandos SQLs enviados

Usar outer join fetching
Otimizando

Problemas

Usar lazy fecthing
• Problema dos n+1 selects (muitos selects!)

Usar outer join fetching
• Problema do produto cartesiano (grandes
conjuntos de dados)
Otimizando

Solucionando problemas de
otimização
Stratégia de Fecthing definida em tempo
de execução
 Batch Fecthing
 Utilizar um cache de segundo nível

Consultas

HIbernate Query Lanuage


Permite que se expresse quase tudo o
que se precisa expressar em SQL,
porém mais orientado a objetos
Três maneiras de se fazer consultas
no Hibernate
HQL
 Criteria
 SQL nativo

HQL


Tornar SQL orientado a objetos

Classes e propriedades ao invés de Tabelas e colunas

Polimorfismo

Associações
Total suporte a operações relacionais

Joins

Projeções

Funções agregadas e agrupamento

Ordenação

SubQueries

Chamadas a funções SQL
HQL

A consulta mais simples possivel HQL
from Filme

Devolva todos os filmes
List filmes = session.createQuery(“from Filme”).list();

As consultas podem ser paginadas
Query query = session.createQuery(“from Filme”);
query.setFirstResult(20);
query.setMaxResults(30);
List filmes = query.list();
HQL

Uma consulta com ordenação
from Locacao l order by l.dataLocacao desc

Caso esteja interessado em um único
resultado
Query query = session.createQuery(
“from Locacao l order by l.dataLocacao desc”);
Locacao locacao = query.uniqueResult();
HQL

Uma consulta com joins
select c from Cliente c left join [fetch] c.locacaoes l
where l.dataLocacao > 3/5/2005


Todos os clientes com suas locações efetuadas após o dia
3
Definição da estratégia de fetching


Com o fetch: Coleções já inicializadas
Sem o fetch: lazy collections
HQL

HQL suporta os mesmos operadores que SQL

Operadores do HQL:



Comparação: =, <>, <, >, >=, <=, between, not
between, in, not in

Nulidade: is null, is not null

Aritméticos: +, -, /, *, %, parênteses
O operador like funciona da mesma forma que
SQL
Pode usar funções SQL se o banco suportar
HQL

Projeções + funções agregadas
(Report Queries)
select c.nome, count(l)
from Cliente c, c.locacoes l
where l.dataLocacao between(:inicio, :fim)
group by c.nome
order by count(l)
HQL

Os dados da consulta anterior serão retornados
em List de Object[]
Consulta comum para a realização de relatórios

Podemos tornar o processo mais elegante

List list = session.createQuery(
“select new ClienteReportRow(c.nome, count(l)) ”
+
“from Cliente c, c.locacoes l ” +
“where l.dataLocacao between(:inicio,
:fim) ” +
“group by c.nome ” +
“order by count(l)”).
setDate(“inicion”, inicio).
setDate(“fim”, fim).list();
HQL
Dessa evitasse o uso de vetores de
objetos
 É necessário que exista uma classe e
um construtor previamente definido

HQL

Consultas não precisam aparecer no código



Na verdade, muitas vezes é melhor que não apareçam
Podem ficar nos metadados e serem chamadas pelo
nome
Usa-se o método getNamedQuery()
List clientes =
session.getNamedQuery(“findClienteByName”)
.setString(“nome”, nome),list()

Mas antes, ela precisa ser declarada em algum
arquivo de mapeamento
<query name=“findClienteByName”><![CDATA[
from Cliente c where c.nome like :nome]]
</query>
Modelagem OO

“Mais classes que tabelas”

Classse Endereco
• Propriedade: rua, numero, bairro...

Rua, numero, bairro,... Colunas da
tabela cliente
<class name="br.org.citi.pec.locadora.Cliente"
table="Clientes">
…
<component name=“endereco”
class=“br.org.citi.pec.locadora.Endereco”>
<property name=“rua” column=“rua”/>
<property name=“numero” column=“numero”/>
…
</component>
</class>
O que mais?
Hibernate também dá suporte a tipos
de dados definidos pelo usuário
 Interceptadores e EventListeners
 Filtros
 Definições explicitas dos SQLs de
insert e update e load (hibernate 3)

...e mais um pouco!
Sobre configuração

Como obter um SessionFactory?
Programaticamente
 Por arquivo XML

Configuração programática
Configuration cfg = new Configuration()
.setProperty("hibernate.dialect",
"org.hibernate.dialect.HSQLDialect").
.setProperty("hibernate.connection.driver_class",
"org.hsqldb.jdbcDriver")
.setProperty("hibernate.connection.url",
"jdbc:hsqldb:file:hsqldb/data")
.setProperty("hibernate.connection.username", "sa")
.setProperty("hibernate.connection.password", "")
.addClass(Filme.class)
.addClass(Cliente.class)
.addClass(Locacao.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Configuração XML
hibernate.cfg.xml
<?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>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">
org.gjt.mm.mysql.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">ftBBvEdiC</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost/lockar</property>
<mapping class="br.org.citi.pec.locadora.Filme"/>
<mapping class="br.org.citi.pec.locadora.Locacao"/>
<mapping class="br.org.citi.pec.locadora.Cliente"/>
</session-factory>
</hibernate-configuration>
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Extras

Hbm2ddl (tool)
Gera o schema do BD a partir das XML
de mapeamentos
 Usado por linha de comando ou pelo ant

<target name="schemaexport">
<taskdef name="schemaexport"
classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
classpathref="project.lib.classpath" />
<schemaexport properties="hibernate.properties"
quiet="yes" text="yes" drop="no" delimiter=";"
output="${basedir}/sql/schema-export.sql">
<fileset dir="src">
<include name="**/*.hbm.xml" />
</fileset>
</schemaexport>
</target>
Exercícios

Ampliar nosso modelo
Exercícios

Crie as classes (JavaBeans/POJO)

Crie os XML de mapeamentos

Implemente as consultas e métodos para retornar

Todos os filmes locados durante um determinado mês

Listagem contendo nome do filme, média das avaliações, e
total de comentários para todos os filmes

Listagem contendo nome do filme mais o número de cópias de
VHS e de DVD desse filme

Listagem contendo nome do filme mais o número de cópias de
VHS e de DVD desse filme locadas em um determinado mês

Todos os clientes que locaram mais de 5 VHS no ultimo mês
(Com as devidas locações carregadas)
Download

Hibernate