Aula 4 (17/03/2015) - Hibernate - Mapeamento Objeto

Propaganda
Hibernate
Mapeamento Objeto-Relacional
Prof. Alexandre Monteiro
Recife
‹#›
Contatos

Prof. Guilherme Alexandre Monteiro Reinaldo

Apelido: Alexandre Cordel

E-mail/gtalk: [email protected]
[email protected]

Site: http://www.alexandrecordel.com.br/fbv

Celular: (81) 9801-1878
Objetivo

Mostrar uma aplicação simples que demonstra o uso de
Hibernate
• O objetivo não é explorar os recursos do Hibernate, mas
apenas colocar o ambiente de sala de aula para funcionar

A aplicação utilizada será uma explanação de
Mapeamento Objeto-Relacional na camada
persistente usando hibernate
Configuração do ambiente

Para demonstrar o uso de Hibernate, precisamos ter no
ambiente de sala de aula:
• Um sistema de gerenciamento de banco de dados (remoto ou
local) com driver JDBC e acesso para criação de tabelas em pelo
menos uma base de dados
-
Usaremos o MYSQL Worbench
MySQLCC
PowerArchitect
PHPMyAdmin (roda localmente e usa o Apache)
• Ambiente Integrado de execução/desenvolvimento Java
-
Usaremos o NetBeans
Eclipse
Jcreator
BlueJ
SGBD

Pode ser qualquer banco de dados com driver JDBC.

Nos exemplos, usaremos MySQL (www.mysql.com)

Use a tela de administração do XAMPP Control para:
• Instalar o Banco de Dados

Use o MySQL Worbench para:
• Criar uma base de dados
teste_hibernate
• Executar queries diretamente no banco
• Criar e verificar o esquema das tabelas
Criação da base de dados

Use a interface do seu MySQL Worbench

1) Crie a seguinte base de dados
teste_hibernate

2) Crie a seguinte tabela
CREATE TABLE `aluno` (
`id_aluno` int(11) NOT NULL,
`nm_aluno` varchar(255) NOT NULL,
`mat_aluno` varchar(255) NOT NULL,
`nota` double DEFAULT NULL,
`dt_cadastro` datetime DEFAULT NULL,
);
Hello World

Esta aplicação simples consiste de
• uma classe Java
• um arquivo de mapeamento XML
• uma tabela de banco de dados SQL (MySQL)

O objetivo é desenvolver o Mapeamento ObjetoRelacional usando Hibernate como framework de
comunicação com um banco de dados.
A classe
package entidade;
public class Aluno {
private int id;
private String nome;
...
public Aluno() {}
public String getNome() {
return this.nome;
}
public void setNome(String nome) {
this.nome = nome;
}
...
// getters e setters e outros construtores
}
A classe

Possui:
• Identificador do aluno(id),
• Nome do aluno (nome)
• ...


É um POJO/Java Bean (Plain Old Java Object ou Velho
e Simples Objeto Java)
Não tem nada a ver com o Hibernate
• Pode ser usado em qualquer aplicação Java.
• Segue as convenções usadas em JavaBeans
Os Meta dados de mapeamento

As informações sobre o mapeamento entre a tabela e a classe
Aluno ficam em um arquivo XML
• Guarde-o no mesmo pacote que a classe (entidade)
• Chame-o de Aluno.hbm.xml
Os Meta dados de mapeamento
<?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>
<class name="entidade.Aluno" table="aluno" catalog="teste_hibernate">
<id name="idAluno" type="java.lang.Integer">
<column name="id_aluno" />
<generator class="identity" />
</id>
<property name=“nome" type="string">
<column name="nm_aluno" length="45" not-null="true" />
</property>
...
<set name="disciplinas" inverse="false" table="aluno_has_disciplina">
<key>
<column name="aluno_id_aluno" not-null="true" />
</key>
<many-to-many entity-name="entidade.Disciplina">
<column name="disciplina_id_disciplina" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Hibernate é produtividade!

Não tenha medo dos metadados XML!
• Siga as convenções que eles se mantêm simples

Pode-se gerar tudo em Hibernate
• O arquivo XML de mapeamento pode ser gerado
automaticamente de classes ou tabelas
• Classes podem ser geradas automaticamente a partir de
tabelas
• Tabelas podem ser geradas automaticamente a partir de
classes
• Outros arquivos de configuração podem ser gerados

Mais adiante apresentaremos ferramentas que
realizam essas tarefas
Arquitetura do Hibernate



Antes de começar, vamos conhecer um pouco da API
A API do Hibernate está organizada nos pacotes e
subpacotes de org.hibernate
Podemos classificar suas interfaces em quatro grupos
• Interfaces chamadas pelas aplicações para realizar operações
CRUD* e queries: Session, Transaction e Query
• Interfaces de configuração: Configuration
• Interfaces de callback: Interceptor, Lifecycle, Validatable
• Interfaces de extensão de mapeamento: UserType,
CompositeUserType, IdentifierGenerator
Arquitetura do Hibernate
Principais interfaces



Cinco interfaces fundamentais são usadas em quase
qualquer aplicação
Servem para armazenar, remover, atualizar e
recuperar objetos persistentes e lidar com transações
Estão listados abaixo na ordem em que (geralmente)
são usadas
• Configuration: carrega dados de configuração
• SessionFactory: obtida de uma Configuration; permite criar
sessões de interação com a camada de persistência
• Session: principal objeto usado para ler, gravar, atualizar,
etc.
• Transaction: camada sobre sistemas de transações nativo
• Query ou Criteria: realizam pesquisa no modelo de objetos
Session

Principal interface usada em aplicações Hibernate
• Todas as operações explícitas de persistência são realizadas
através de um objeto Session

Objeto leve
• Fácil de criar
• Fácil de destruir

Objetos
Session
não são threadsafe
• Devem ser usados em um único thread
• Para threads adicionais, crie sessions adicionais
SessionFactory

Uma aplicação obtém uma Session a partir de uma
SessionFactory
• Objeto pesado;
• Lento para inicializar e destruir;
• Geralmente tem-se apenas uma para toda a aplicação;
• Deve-se ter uma SessionFactory para cada banco de dados
utilizado.

Realiza cache de comandos SQL, dados e metadados
usados em tempo de execução
Configuration


É o ponto de partida para iniciar o Hibernate
Inicializado com propriedades de configuração do
sistema
• Especifica a localização de dados e arquivos de mapeamento,
objetos, configuração do banco de dados, pool de conexões,
dialeto do SQL do banco, etc.
• Geralmente obtém a configuração via arquivos .properties,
XML ou propriedades dinâmicas

Cria a SessionFactory
Transaction

Abstração da implementação de transações usada no
código
• A implementação real pode ser uma transação JTA, JDBC, etc.

Essencial para garantir a portabilidade de aplicação
entre diferentes ambientes e containers
• Encapsula o objeto de transação nativo em servidores de
aplicação ou outros ambientes controlados
Query e Criteria



Permite a realização de consultas ao banco
Consultas Query são escritas em HQL (Hibernate Query
Language) ou no SQL nativo do banco.
Objetos Query são usados para
• Passar parâmetros para a consulta em HQL
• Filtrar resultados
• Executar os comandos da consulta


Criteria é uma alternativa que faz a mesma coisa
usando métodos da API (em Java, em vez de HQL)
Uma Query só pode ser usada dentro de sua sessão
Usando a API do Hibernate em 3 passos

1) Primeiro é preciso obter um objeto de sessão Session.
Session session = ...;
• Através desse objeto é possível realizar operações de leitura e
gravação

2) Para gravar, crie um objeto da maneira usual e grave
na sessão usando save()
Aluno aluno = new Aluno();
aluno.setNome(“Alexandre”);
session.save(aluno);

3) Para ler todas as mensagens, envie um query via
createQuery().list()
List alunos = session.createQuery(“from Aluno”).list();
Manipulação do objeto persistente

Leitura de uma mensagem específica
Aluno aluno = (Aluno) session.load(Aluno.class, 1);

Alteração da mensagem acima (sem usar Session)
aluno.setNome(“Alexandre Cordel");
Aluno outroAluno = new Aluno(“Leonardo");
A Session deve estar aberta para a persistência ocorrer!
Manipulação do objeto persistente

Leitura de várias mensagens do banco
Session newSession = getSessionFactory().openSession();
Transaction newTransaction = newSession.beginTransaction();
List alunos = session.createQuery("from Aluno as al order by al.nm_alunoasc").list;
System.out.println( alunos.size() + " aluno(s) encontrado:" );
for ( Iterator iter = alunos.iterator(); iter.hasNext(); ) {
Aluno aluno = (Aluno) iter.next();
System.out.println( aluno.getNome() );
}
newTransaction.commit();
newSession.close();
Queries


Os comandos do slide anterior geram queries no Hibernate que
conceitualmente* equivalem aos queries abaixo
Atualização
select al.id_aluno, al.nm_aluno from ALUNO al where al.id_aluno = 1
insert into aluno (id_aluno, nm_aluno, mat_aluno)
values (2, ‘Biu', ‘1232014’)
update aluno
set nm_aluno = ‘Biu Gaites‘ where id_aluno = 2
select al.id_aluno, al.nm_aluno
from aluno al order by al.nm_aluno asc
* O Hibernate poderá gerar queries diferentes que fazem a mesma coisa
Como configurar

Para colocar para funcionar a aplicação exemplo, é preciso
configurar o Hibernate no ambiente de execução
• Hibernate pode ser configurado para rodar em praticamente
qualquer aplicação Java
• Não precisa estar em servidor J2EE
• O único servidor necessário é um SGBD

Ambientes gerenciados: transações demarcadas
declarativamente; conexões gerenciadas pelo servidor
• Servidores de aplicação, por exemplo, o JBoss

Ambientes não-gerenciados: a aplicação gerencia conexões de
banco de dados e demarca transações
• Aplicações standalone fora de servidor
• Servidores Web, por exemplo, o Tomcat
Criação de um SessionFactory

Crie uma única instância de Configuration
Configuration cfg = new Configuration();

Passe as propriedades para configurar o ambiente
cfg.addResource(“entidade/Aluno.hbm.xml");
Properties p = System.getProperties();
p.load(
ClassLoader.getSystemResourceAsStream("hibernate.properties")
);
cfg.setProperties( p );

Obtenha a SessionFactory
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
Convenção



Arquivos de mapeamento geralmente têm (por
convenção) a extensão .hbm.xml
Deve-se ter um arquivo por classe (também por
convenção) e mantê-lo no mesmo diretório (pacote)
que as classes compiladas
Se for seguida essa convenção, pode-se carregar as
classes da forma:
cfg.addClass(entidade.Aluno.class)
cfg.addClass(entidade.Disciplina.class)
E de outras formas, usando configuração em XML
• Então, siga a convenção!
Configuração em ambientes não
gerenciados

Em ambientes não
gerenciados, a aplicação é
responsável por obter
conexões JDBC
• Deve-se sempre usar um pool
de conexões para obter uma
conexão
• O Hibernate faz interface com o
pool isolando-o da aplicação
Fonte: Bauer/King. Hibernate In Action, Manning, 2005
hibernate.properties


Há várias formas de configurar o Hibernate; uma delas é usar um
arquivo hibernate.properties
O arquivo de configuração abaixo tem três partes
• A primeira inicializa o driver JDBC (banco Postgres)
• A segunda descreve o dialeto do SQL usado
• A terceira inicializa o Hibernate para usar o serviço C3PO como pool de
conexões (O C3PO é distribuído com o Hibernate)
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost/teste_hibernate
hibernate.connection.username=root
hibernate.connection.password=
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=300
hibernate.c3p0.max_statements=50
hibernate.c3p0.idle_test_period=3000
Arquivos .properties

Arquivos .properties são equivalentes à classe java.util.Properties
• Propriedades carregadas tornam-se propriedades de objeto
java.util.Properties

Devem declarar uma propriedade (nome=valor) por linha
• Nomes são declarados na primeira coluna até o = ou :, após o qual é
declarado o valor
• Espaços são significativos depois do =
• Uma quebra de linha termina a propriedade
• \ (contra barra) é símbolo de escape (escapa inclusive quebra de linha)

Para carregar
• Ponha no Classpath para carga automática pela aplicação (quando
suportado)
• Carregamento explícito (do Classpath)
Properties p = new Properties();
p.load(Classloader.getSystemResourceAsStream(“arquivo”));

Veja mais nos Java Docs de java.util.Properties
Referência: propriedades JDBC

hibernate.connection.driver_class=nome.de.Classe
• classe do driver (deve estar no classpath)

hibernate.connection.url=url:jdbc
• jdbc URL

hibernate.connection.username=nome
• usuário do banco de dados

hibernate.connection.password=senha
• senha do banco de dados

hibernate.connection.pool_size=numero
• número máximo de conexões

hibernate.c3po.*
• diversas propriedades para configurar o pool C3PO

hibernate.proxool.*
• diversas propriedades para configurar o pool Proxool

hibernate.dbcp.ps.*
• diversas propriedades para configurar o pool DBCP (com PreparedStatement)
Referência: propriedades de
configuração

hibernate.dialect=nome.de.Classe
• Implementação de um dialeto (veja slide seguinte)

hibernate.show_sql=true|false
• Útil para debugging. Escreve todo o SQL gerado para o console.

hibernate.max_fetch_depth=numero
• Define uma profundidade máxima para a árvore de recuperação de outer-join. 0
desabilita outer-join como default. Evite valores maiores que 3.

hibernate.connection.propriedade=valor
• Passa propriedades para DriverManager.getConnection() (configuração de JDBC)
Referência: dialetos SQL suportados

hibernate.dialect=org.hibernate.dialect.<nome>
onde <nome> pode ser qualquer um dos presentes no pacote
org.hibernate.dialect
Para rodar a aplicação

Coloque no Classpath
• hibernate.properties
• hibernate-xxx.jar e outros JARs requeridos (pegue todos os
JARs da distribuição do Hibernate)
• Driver do banco de dados usado

Inicie o banco de dados (se já não estiver iniciado)

Execute a aplicação
hibernate.cfg.xml

É uma outra forma (melhor) de prover informações de
configuração à aplicação
•Também deve ser guardada no Classpath

Tem precedência sobre hibernate.properties
•Propriedades definidas nos dois serão
sobrepostas

Define
•Propriedades da Session Factory usando
<property> (os nomes são iguais, sem o
prefixo hibernate.*)
•Arquivos de mapeamento de instâncias
hibernate.cfg.xml e mapeamento

Para mapear automaticamente:
• No arquivo use o tag <mapping resource=“xx” /> para
descrever a localização dos mapeamentos
• Na inicialização via Configuration, use conf.configure()
(onde conf é objeto Configuration) em vez de addClass() ou
addResource()

Exemplo de uso
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Exemplo de 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>
<!-- properties -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">
jdbc:mysql://localhost/teste_hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">false</property>
<!-- mapping files -->
<mapping resource=“entidade/Aluno.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Código de um main() completo
Configuration cfg = new Configuration();
cfg.addClass(Message.class);
Properties p = System.getProperties();
p.load(
ClassLoader.getSystemResourceAsStream("hibernate.properties")
);
cfg.setProperties( p );
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Aluno aluno = new Aluno();
aluno.setNome(“Nome do Aluno");
session.save(aluno);
tx.commit();
session.close();
Básico sobre mapeamento

O DTD é declarado em cada arquivo

O elemento raiz é <hibernate-mapping>

O mapeamento classe-tabela é feito no elemento
<class>
• Pode-se ter várias <class> em um <hibernate-mapping>
• Recomenda-se (convenção) ter somente um <class>; assim, o
nome do arquivo deve ser NomeDaClasse.hbm.xml


Um elemento <id> em cada <class> mapeia o
identificador do objeto a uma chave primária da
tabela
Os elementos <property> servem para mapear as
colunas restantes às propriedades do objeto
<property>

Um mapeamento típico define
• Nome de propriedade JavaBean. Ex: name
• Nome de coluna. Ex: NAME
• Nome de tipo Hibernate. Ex: string

A declaração explícita de tipos pode ser opcional
• O comportamento default é converter o tipo Java no tipo
Hibernate mais próximo

Declaração explícita do nome da coluna do banco de
dados pode ser opcional
• Se não for declarado explicitamente, o Hibernate assume que
o nome da coluna é igual ao nome da propriedade JavaBean
<property>

Declarações equivalentes:
<property name="description"
column="DESCRIPTION"
type="string"/>
<property name="description"
column="DESCRIPTION"/>
<property name="description" />
<property name="description"
type="string">
<column name="DESCRIPTION"/>
</property>
<id>

Semelhante a <property>

Porém representa a chave primária do objeto

valor retornado por

Acesso (convenção)
session.getIdentifier(objeto)
• Declare getId() com acesso público
• Declare setId() com acesso privativo (a identidade de um objeto
nunca deve mudar)

Por causa do mapeamento, a identidade BD entre objetos a
e b pode ser testada usando
a.getId().equals(b.getId())
<generator>







Chaves podem ser geradas pelo Hibernate
native: automaticamente escolhe a estratégia mais adequada
(dentre as outras opções abaixo) de acordo com os recursos
disponíveis no banco de dados usado
identity: gera inteiro (até tamanho long) e suporta colunas identity
em DB2, MySQL, MS SQL Server, HSQLDB, Sybase, Informix
sequence: gera inteiro (até long) e é compatível com o sequence de
Oracle, DB2, SAP DB, McKoi, Fifrebird ou generator em InterBase
increment: controle nativo do Hibernate; é eficiente se a aplicação
Hibernate tem acesso exclusivo aos dados (gera inteiro até long)
hilo: usa um algorítmo eficiente (high-low) para gerar
identificadores inteiros (até long) unívocos apenas para um banco
específico.
Há outras menos usadas; também é possível criar novas
Resumo: tags de mapeamento
básico

hibernate-mapping>
• Elemento raiz. Sempre presente

<class>
• Usada dentro de <hibernate-mapping>
• Define mapeamento de uma classe a tabela
• Pode haver vários em um <hibernate-mapping> mas a convenção
recomendada é haver apenas um por arquivo

<id>
• Mapeamento de identidade (coluna de chave-primária a uma
propriedade de identidade da classe)
• Usada dentro de <class>

<generator>
• Usado dentro de <id> para gerar chaves primárias

<property>
• Mapeamento simples de propriedade - coluna
Exercicio

Testar o exemplo mostrado

Testar as demais operações do session mostradas
• load()
• createQuery().find()
Exercicio



Vamos implementar suporte a persistência para a
seguinte classe (Criar classe, tabela e mapeamento)
Vamos implementar um DAO para as classes acima
usando o Hibernate.
E teste-o!
Referências

Hibernate in Action
Download