Conexão Java 2006 Mini

Propaganda
Conexão Java 2006
Mini-curso Hibernate
Sérgio Luís Lopes Júnior
Caelum – www.caelum.com.br
Neste tutorial, você irá aprender a:
- usar a ferramenta de ORM Hibernate
- gerar as tabelas em um banco de dados qualquer a partir de suas classes de modelo
- automatizar o sistema de adicionar, listar, remover e procurar objetos no banco
- utilizar anotações para facilitar o mapeamento de classes para tabelas
- criar classes de dao bem simples utilizando o hibernate
- utilizar relacionamentos entre tabelas
Introdução
A utilização de código SQL dentro de uma aplicação agrava o problema da
independência de plataforma de banco de dados e complica, em muito, o trabalho de
mapeamento entre classes e banco de dados relacional.
HIBERNATE
O Hibernate abstrai o código SQL da nossa aplicação e permite escolher o tipo de
banco de dados enquanto o programa está rodando, permitindo mudar sua base sem
alterar nada no seu código Java.
Além disso, ele permite criar suas tabelas do banco de dados de um jeito bem
simples, não se fazendo necessário todo um design de tabelas antes de desenvolver
seu projeto que pode ser muito bem utilizado em projetos pequenos.
Já projetos grandes onde o plano de ação padrão tomado pelo Hibernate não
satisfaz as necessidades da empresa (como o uso de select *, joins etc), ele possui
dezenas de otimizações que podem ser feitas para atingir tal objetivo.
O Hibernate é o framework de mapeamento objeto relacional mais utilizado em
projetos Java. Seu criador Gavin King se juntou a Marc Flery do grupo JBoss, e agora o
Hibernate faz parte do JBoss group, que por sua vez foi vendido para a corporação Red
Hat.
Anotações, EJB3 e Persistence API
Fazer o mapeamento objeto relacional com o Hibernate era muito trabalhoso até
a chegada das anotações do java5: você precisava criar arquivos XML de mapeamento,
especificando as relações entre as entidades, nome de colunas, tabelas e muitos
outros.
Para não fazer isso tudo na mão o XDoclet ajudava muito, porém abria espaço
para erros de digitação. Muitos plugins para as IDEs foram lançados, mas faltava algo
para criar uma real facilidade.
A JSR 220, que especifica o EJB3, separou a parte de Entity Beans na Persistence
API (javax.persistence), onde define um EntityManager que faz o papel das antiga
Homes, assim como uma EJB query language renovada e um conjunto de anotações
para fazer o mapeamento objeto relacional.
Essa API é desacoplada da API dos EJBs, fazendo com que a API não precise de
um container Java EE para ser utilizado. Gavin King, como um dos líderes dessa JSR,
foi implementando a Persistence API em cima do Hibernate enquanto a JSR ia sendo
desenvolvida. Dia 1o de maio de 2006, com o lançamento da JSR, o Hibernate já
possui implementado a grande maioria das necessidades especificadas na JSR.
Por esse motivo uma grande parte de imports que vamos usar serão
javax.persistence e não apenas org.hibernate.
Ambiente usado
Usaremos neste projeto a IDE livre Eclipse (www.eclipse.org) e Java 5. A versão
do Hibernate que usamos é a 3.2.1.
Como Banco de Dados, usaremos o Apache Derby, um banco escrito totalmente
em Java e que pode ser distribuído junto com sua aplicação.
Criando seu projeto
Para criar seu projeto, é necessário baixar os arquivos .jar necessários para rodar
o Hibernate e colocá-los no classpath do mesmo.
O site oficial do hibernate é o www.hibernate.org e lá você pode baixar a
última versão estável do mesmo na seção Download. Após descompactar esse arquivo,
basta copiar todos os jars para o nosso projeto.
HIBERNATE
ANNOTATIONS
Ainda falta baixar as classes correspondentes ao HibernateAnnotations, que
iremos utilizar para gerar o mapeamento entre as classes Java e o banco de dados.
Eles são encontrados também no site do hibernate e contem outros jars que devemos
colocar no nosso projeto.
Exercício
1) Abra o eclipse e selecione o workspace padrão.
2) Crie um novo projeto Java:
File -> New -> Project -> Java Project
Clique em Next e na próxima tela marque:
Project name: hibernate
Create separate source and output folders
Clique em Finish.
3) Crie uma pasta lib dentro do seu projeto:
Clique com o botão direito no nome do projeto e vá em New -> Folder e crie uma
pasta chamada lib
4) Copie os jars do hibernate, hibernate-annotations e do derby para o seu
diretório lib:
- Clique com o botão direito na pasta lib e clique em Import
- Selecione Archive File (na aba General), clique em Next
- Selecione o arquivo hibernate-jar.zip
- Clique em Select All e depois em Finish
5) Precisamos adicionar os jars no class path. Expanda a pasta lib e selecione
todos os jars. Clique com o botão direito e vá em: Build Path -> Add to build path...
Propriedades do banco
O arquivo hibernate.properties é um arquivo de propriedades para
configurarmos as opções do hibernate. Há centenas de configurações possíveis, como
avançados controles de cache, transações e outros.
Para nosso sistema, precisamos de quatro linhas básicas, que configuram o
banco, o driver, o usuário e senha, que já conhecemos, e uma linha adicional, que diz
para o hibernate qual dialeto de SQL ele deve “falar”: o dialeto do hsqldb.
Além disso, vamos colocar uma opção para que o hibernate exiba os comandos
SQL que ele executar. O arquivo final fica da seguinte maneira:
hibernate.dialect org.hibernate.dialect.DerbyDialect
hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver
hibernate.connection.url jdbc:derby:bancodedados;create=true
hibernate.connection.username
hibernate.connection.password
hibernate.show_sql true
hibernate.format_sql true
Ele deve ser colocado no classpath de sua aplicação. No nosso caso, basta colocálo no diretório src.
Além disso, vamos copiar também um arquivo chamado log4j.properties para
configurar o log do hibernate; usamos o arquivo padrão que vem junto com o
hibernate.
Exercícios
1-) Para economizarmos tempo, copie o arquivo properties citado acima para
dentro do diretório src de nosso projeto:
-
Clique com o botão direito na pasta src e clique em Import
Selecione Archive File (na aba General), clique em Next
Selecione o arquivo hibernate-properties.zip
Clique em Select All e depois em Finish
2) Abra o arquivo hibernate.properties copiado e veja seu conteúdo.
Em casa: Baixando os arquivos necessários
Vá em www.hibernate.org e baixe o hibernate e o hibernate-annotations.
Descompacte os dois arquivos baixados. Os jars necessários estão na raiz de cada
pasta criada e dentro de suas respectivas pastas lib.
Os arquivos hibernate.properties e o log4j.properties estão na pasta src dentro
da pasta onde você descompactou o hibernate.
O Derby você baixa em derby.apache.org. Copie o arquivo derby.jar de dentro da
pasta lib dele.
Modelo
Como exemplo, vamos criar um sistema de controle de Produtos para uma loja.
Iniciamos nosso trabalho modelando uma classe para representar essa entidade
Produto do sistema.
A classe produto será uma classe JavaBean simples, como atributos privados e
métodos de acesso get e set.
package br.com.caelum.hibernate;
public class Produto {
private
private
private
private
Long id;
String nome;
String descricao;
double preco;
// gets e sets aqui
}
Além de termos a classe modelando a entidade Produto no nosso programa Java,
precisamos de alguma forma de persistí-lo no banco de dados. Normalmente,
criaríamos a tabela em SQL (create table ...) para guardar os produtos. Vamos usar o
hibernate para isso. Mas antes precisamos configurar a classe para o hibernate saber
usá-la.
Configurando a classe/tabela Produto
Antigamente (até a versão 2 do hibernate) a configuração era feito somente
através de arquivos xml, o que era bem chato, e utilizávamos de uma ferramenta
chamada Xdoclet que criava tais xmls através de comentários especiais.
Hoje em dia o Xdoclet foi substituido pelas anotações do Java 5. A grande
diferença entre os dois – anotações e comentários – é que as anotações são bem
estruturadas, seguem um padrão e são mantidas em tempo de execução, enquanto os
comentários são perdidos em tempo de compilação, que impossibilita descobrir em
tempo de execução o que havia sido comentado.
O código a seguir coloca nossa classe na tabela "Produto" e seta algumas
propriedades e o id (chave primária).
Atenção: toda classe que vai trabalhar com o Hibernate precisa de um (ou mais)
campo(s) que será(ão) a chave primária (composta ou não).
package br.com.caelum.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Produto {
@Id
@GeneratedValue
private Long id;
private String nome;
private String descricao;
private double preco;
// gets e sets aqui
}
A especificação do EJB3 define tais anotações e possui diversas opções que
podemos utilizar em nosso projeto. Sempre que possuir alguma dúvida em relação as
anotações lembre-se de ler a tal especificação. O API comum das anotações usadas
pelo Hibernate e o EJB3 é o Java Persistence API, no pacote javax.persistence.
Exercícios
1-) Crie uma classe chamada Produto no pacote br.com.caelum.hibernate:
File -> New -> Class
Coloque o nome do pacote como br.com.caelum.hibernate
Coloque o nome da classe como Produto
2) Escreva a classe como vimos acima:
package br.com.caelum.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Produto {
@Id
@GeneratedValue
private Long id;
private String nome;
private String descricao;
private double preco;
}
3-) Gere os getters e setters usando o eclipse:
- Selecione os atributos da classe e vá em:
- Source -> Generate Getters and Setters
- Clique em Select All e depois em Finish.
Configurando
Qualquer programa que use o hibernate precisa, antes de qualquer coisa,
cofigurá-lo. Fazemos isso através da classe AnnotationConfiguration.
// cria a configuração do hibernate
AnnotationConfiguration conf = new AnnotationConfiguration();
A partir daí podemos adicionar quantas classes desejarmos a nossa configuração.
// adiciona a classe Produto
conf.addAnnotatedClass(Produto.class);
O Hibernate requer que descrevamos como a classe se relaciona com as tabelas
no banco de dados e fizemos isso através das anotações do Hibernate. Ao adicionarmos
a classe Produto na nossa configuração, o Hibernate lê essas configurações.
XML
Essa configuração poderia ser feita através de um arquivo xml chamado
hibernate.cfg.xml, e em vez de utilizarmos as chamadas ao método addAnnotatedClass
iríamos executar o método configure() .
Criando as tabelas
SCHEMA
EXPORT
Vamos criar um programa que gera as tabelas do banco. Dada uma configuração,
a classe SchemaExport é capaz de gerar o código DDL de criação de tabelas em
determinado banco (no nosso caso, o hsqldb).
Para exportar tais tabelas, fazemos uso do método create que recebe dois
argumentos booleanos. O primeiro diz se desejamos ver o código DDL e o segundo se
desejamos executá-lo realmente.
// gera a tabela no banco
new SchemaExport(conf).create(true, true);
O código final da classe GeraTabelas, incluindo a configuração, você vê no
exercício abaixo:
Exercícios
1-) Crie a classe GeraTabelas:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como GeraTabelas
2) Escreva o método main e, dentro dele, faça a configuração do hibernate e
depois gere a tabela, da seguinte forma:
package br.com.caelum.hibernate;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class GeraTabelas {
public static void main(String[] args) {
// cria a configuração do hibernate
AnnotationConfiguration conf = new AnnotationConfiguration();
// adiciona a classe Produto
conf.addAnnotatedClass(Produto.class);
}
// gera a tabela no banco
new SchemaExport(conf).create(true, true);
}
3-) Crie suas tabelas executando o código anterior.
Clique com o botão direito no nome da classe, vá em:
Run As... -> Java Application
O Hibernate deve reclamar que não configuramos nenhum arquivo de log para
ele (dois warnings, ignore-os) e mostrar o código SQL que ele executou no banco.
Sessões
O hibernate nãp te dá acesso direto às conexões com o banco de dados. Ele
trabalha com a idéia de sessões de uso do banco. Para efetuar alguma operação no
banco (INSERT, SELECT, ...) você precisa, antes, obter uma sessão do hibernate.
O Hibernate provê uma fábrica de sessões, onde você pode obter uma sessão
quando
quiser.
Na
configuração
do
hibernate,
chamamos
o
método
buildSessionFactory() que nos devolve uma SessionFactory.
SessionFactory factory = conf.buildSessionFactory();
factory.close();
O Hibernate gera sessões através dessa factory. Essas sessões são responsáveis
por se conectar ao banco de dados e persistir e buscar objetos no mesmo.
A maneira mais simples de abrir uma nova sessão e fechar a mesma é:
Session session = factory.openSession();
session.close();
Hibernate Session Factory
Sempre que formos trabalhar com o Hibernate, teremos que configurá-lo, obter a
fábrica de sessões e depois obter uma sessão. Ao invés de espalhar esse código por
todo nosso sistema, vamos encapsulá-lo em algum lugar, em alguma classe.
Vamos criar uma classe HibernateFactory que cuidará de:
- instanciar a SessionFactory do Hibernate;
- nos dar Sessions do hibernate quando precisarmos.
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateFactory {
private static SessionFactory factory;
static {
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.addAnnotatedClass(Produto.class);
factory = cfg.buildSessionFactory();
}
public Session getSession() {
return factory.openSession();
}
}
O bloco estático das linhas 4 a 8 cuidará de configurar o Hibernate e pegar uma
SessionFactory. Lembre-se que o bloco estático é executado automaticamente
quando a classe é carregada pelo Class Loader e só neste momento; ele não será
executado outras vezes, como quando você der new HibernateFactory().
Ou seja, a configuração do Hibernate será feita uma única vez em todo seu
programa.
O método getSession
SessionFactory do Hibernate.
devolverá
uma
Session,
conseguida
através
do
Exercícios
1-) Crie a classe HibernateFactory:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como HibernateFactory
2-) Implemente a classe HibernateFactory como está na seção anterior. No
momento de importar Session lembre-se que não é a classic!
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateFactory {
private static SessionFactory factory;
static {
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.addAnnotatedClass(Produto.class);
factory = cfg.buildSessionFactory();
}
public Session getSession() {
return factory.openSession();
}
}
Erros comuns
1-) O erro mais comum ao criar a classe HibernateFactory está em importar
org.hibernate.classic.Session ao invés de org.hibernate.Session. Uma vez que o
método openSession devolve uma Session que não é do tipo classic, o Eclipse pede
para fazer um casting. Não faça o casting! Remova o seu import e adicione o import
correto.
Salvando novos objetos
Depois de todos esses passos de configuração e etc, vamos agora efetivamente
trabalhar com o banco de dados, inserindo um novo Produto.
Através de um objeto do tipo Session é possível gravar novos objetos do tipo
Produto no banco. Para tanto basta criar o objeto e depois utilizar o método save.
Mas como usamos um banco transacional, precisamos usar Transações. Isso é
feito com o beginTransaction() na session e depois com o commit() para comitar.
// cria um produto p e o popula
Produto p = new Produto();
p.setNome("Nome aqui");
p.setDescricao("Descrição aqui");
p.setPreco(100.50);
// obtém uma sessão
Session session = new HibernateFactory().getSession();
// Inicia uma transação
Transaction transaction = session.beginTransaction();
// salva o produto
session.save(p);
// Comita a transação
transaction.commit();
// veja o id gerado
System.out.println("ID do produto: " + p.getId());
session.close();
Exercícios
1-) Crie a classe AdicionaProduto:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como AdicionaProduto
2) Implemente o método main para adicionar um produto no banco de dados,
conforme vimos acima:
package br.com.caelum.hibernate;
import org.hibernate.Session;
public class AdicionaProduto {
public static void main(String[] args) {
// cria um produto p e o popula
Produto p = new Produto();
p.setNome("Nome aqui");
p.setDescricao("Descrição aqui");
p.setPreco(100.50);
// obtém uma sessão
Session session = new HibernateFactory().getSession();
// Inicia uma transação
Transaction transaction = session.beginTransaction();
// salva o produto
session.save(p);
// Comita a transação
transaction.commit();
// veja o id gerado
System.out.println("ID do produto: " + p.getId());
session.close();
}
}
3-) Adicione um produto executando o código anterior.
Clique com o botão direito no nome da classe, vá em:
Run As... -> Java Application
O Hibernate deve mostrar o código SQL que ele executou no banco.
4-) (opcional) Adicione outros produtos no banco (altere os dados no programa e
rode-o outras vezes).
Buscando pelo id
Para buscar um objeto pela chave primária, no caso o seu id, utilizamos o
método load, conforme o exemplo a seguir:
// procura o produto de id 2
Produto p = (Produto) session.load(Produto.class, 1L);
// imprime o nome do Produto
System.out.println(p.getNome());
Exercício
1) Crie uma classe BuscaProduto:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como BuscaProduto
2) Crie o método main e busque um Produto pelo id:
package br.com.caelum.hibernate;
import org.hibernate.Session;
public class BuscaProduto {
public static void main(String[] args) {
// obtém uma sessão
Session session = new HibernateFactory().getSession();
// procura o produto de id 2
Produto p = (Produto) session.load(Produto.class, 1L);
// imprime o nome do Produto
System.out.println(p.getNome());
}
session.close();
}
3) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Listando todos os produtos
Vamos listar todos os produtos existentes no banco de dados. Para isso, vamos
usar o método createCriteria de Session que cria um Criteria. Através de um Criteria,
temos acesso a diversas operações no banco de dados; uma delas é listar tudo com o
método list().
Dada uma Session, para listarmos todos os produtos fazemos:
// obtém lista de todos os produtos
List<Produto> produtos = session.createCriteria(Produto.class).list();
Depois, basta percorrer essa lista e imprimir todos os nomes, por exemplo:
// percorre os produtos e imprime o nome de cada um
for (Produto p : produtos) {
System.out.println(p.getNome());
}
Exercício
1) Crie uma classe ListaProdutos:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como ListaProdutos
2) Crie o método main e busque todos os produtos do banco:
package br.com.caelum.hibernate;
import java.util.List;
import org.hibernate.Session;
public class ListaProdutos {
public static void main(String[] args) {
Session session = new HibernateFactory().getSession();
// obtém lista de todos os produtos
List<Produto> produtos = session.createCriteria(Produto.class).list();
// percorre os produtos e imprime o nome de cada um
for (Produto p : produtos) {
System.out.println(p.getNome());
}
}
session.close();
}
3) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Buscando com WHERE em HQL
No exemplo anterior, usamos a chamada Criteria API, uma API do hibernate que
permite que busquemos no banco através da chamada de métodos, sem escrever SQL.
Embora a Criteria API seja muito poderosa e seja virtualmente possível fazer tudo
com ela, há ainda uma segunda possibilidade que eventualmente pode ser mais
simples e direta: o uso de uma linguagem de queries como o SQL.
O problema de usarmos SQL diretamente, porém, é que, como vimos, ele é
dependente de banco de dados. Para solucionar isso, o hibernate criou uma linguagem
de queries própria, a HQL, ou Hibernate Query Language.
A grande vantagem é que ela é extremamente semelhante ao SQL que estamos
acostumados mas é portável. Ou seja, na hora de executar realmente no banco, o
hibernate traduz o comando HQL para o SQL específico do banco em questão.
Para buscarmos os produtos usando alguma cláusula WHERE, por exemplo buscar
apenas os produtos de id maior que 1, podemos fazer:
// obtém lista dos produtos com id maior que 1
List<Produto> produtos = session.createQuery("from Produto where id > 1").list();
Exercício
1) Crie uma classe ListaProdutosHQL:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como ListaProdutosHQL
2) Crie o método main e busque no banco os produtos com id maior que 1
usando HQL:
package br.com.caelum.hibernate;
import java.util.List;
import org.hibernate.Session;
public class ListaProdutosHQL {
public static void main(String[] args) {
Session session = new HibernateFactory().getSession();
// obtém lista dos produtos com id maior que 1
List<Produto> produtos =
session.createQuery("from Produto where id > 1").list();
// imprime nome e id de cada produto
for (Produto p : produtos) {
System.out.println(p.getId() + " - " + p.getNome());
}
session.close();
}
}
3) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Remoção (DELETE)
Assim como inserir usando o Hibernate é muito simples, remover também é
bastante simples. Basta chamarmos o método delete() na session passando o objeto
que queremos remover. No nosso caso, passamos o Produto a ser removido.
Cuidado que, assim como em um DELETE normal, sempre que vamos remover
alguém precisamos dizer qual é o id dele. Então nosso Produto precisa estar com o id
setado.
Não se esqueça também que precisamos de uma Transaction para executar algo
no banco. O código final fica:
// cria um Produto e seta seu id
Produto p = new Produto();
p.setId(0L); // lembre que id é um Long!
// obtém sessão
Session session = new HibernateFactory().getSession();
// abre transação
Transaction transaction = session.beginTransaction();
// apaga o produto
session.delete(p);
// comita a transação
transaction.commit();
session.close();
Exercício
1) Crie uma classe RemoveProduto:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como RemoveProduto
2) Crie o método main e remova o produto de id 0:
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class RemoveProduto {
public static void main(String[] args) {
// cria um Produto e seta seu id
Produto p = new Produto();
p.setId(0L); // lembre que id é um Long!
// obtém sessão
Session session = new HibernateFactory().getSession();
// abre transação
Transaction transaction = session.beginTransaction();
// apaga o produto
session.delete(p);
// comita a transação
transaction.commit();
session.close();
}
}
3) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Uma categoria
E se cada Produto na nossa loja tivesse uma Categoria? Ou seja, um
relacionamento muitos para um? Com o hibernate, é muito fácil criar relacionamentos
entre entidades.
Começamos criando uma classe para representar uma Categoria com, por
exemplo, id e nome. Como ela é uma classe a ser gerenciada pelo Hibernate,
marcamos as anotações apropriadas. A classe final ficará assim:
package br.com.caelum.hibernate;
import
import
import
import
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
@Entity
public class Categoria {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String nome;
}
// gets e sets
Repare que ela é muito parecida com a classe Produto.
Exercício
1-) Crie uma classe chamada Categoria no pacote br.com.caelum.hibernate:
File -> New -> Class
Coloque o nome do pacote como br.com.caelum.hibernate
Coloque o nome da classe como Categoria
2) Escreva a classe como vimos acima:
package br.com.caelum.hibernate;
import
import
import
import
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
@Entity
public class Categoria {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
}
private String nome;
3-) Gere os getters e setters usando o eclipse:
- Selecione os atributos da classe e vá em:
- Source -> Generate Getters and Setters
- Clique em Select All e depois em Finish.
Produto tem uma Categoria
No nosso sistema, cada Produto possui uma Categoria. Em Java, representamos
isso com um atributo na classe Produto. Ou seja, colocamos um atributo do tipo
Categoria dentro de Produto (e geramos get e set para ele).
Mas precisamos, além disso, instruir o hibernate de que estamos fazendo na
verdade um relacionamento Muitos para Um no banco de dados também. Fazemos isso
com uma anotação simples, a @ManyToOne no atributo categoria.
A classe Produto, com as modificações fica:
package br.com.caelum.hibernate;
import
import
import
import
import
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
javax.persistence.ManyToOne;
@Entity
public class Produto {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String nome;
private String descricao;
private double preco;
@ManyToOne
private Categoria categoria;
}
// gets e sets aqui
Exercício
1) Abra sua classe Produto. Acrescente um atributo do tipo Categoria chamado
categoria. Marque esse atributo com a anotação @ManyToOne:
@ManyToOne
private Categoria categoria;
2) Gere get e set para este novo atributo. Selecione o atributo que você acabou
de criar e vá em:
- Source -> Generate Getters And Setters
- Cliquem em Select All e depois em Finish
3) O código final de sua classe Produto deve estar assim:
package br.com.caelum.hibernate;
import
import
import
import
import
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
javax.persistence.ManyToOne;
@Entity
public class Produto {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String nome;
private String descricao;
private double preco;
@ManyToOne
private Categoria categoria;
}
// gets e sets aqui
Recriando as tabelas
Agora que adicionamos um campo novo na tabela Produto e criamos uma nova
classe a ser persistida pelo hibernate, precisamos recriar as tabelas.
Vamos usar a classe GeraTabelas que fizemos anteriormente. Precisamos apenas
indicar, na nossa configuração, que agora temos, além de Produto, também Categoria:
// cria a configuração do hibernate
AnnotationConfiguration conf = new AnnotationConfiguration();
// adiciona as entidades
conf.addAnnotatedClass(Produto.class);
conf.addAnnotatedClass(Categoria.class);
// gera o esquema do banco
new SchemaExport(conf).create(true, true);
Exercício
1) Abra sua classe GeraTabelas. Logo depois de adicionar o Produto à
configuração, adicione a Categoria também. O código final de sua classe deve ser:
package br.com.caelum.hibernate;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class GeraTabelas {
public static void main(String[] args) {
// cria a configuração do hibernate
AnnotationConfiguration conf = new AnnotationConfiguration();
// adiciona as entidades
conf.addAnnotatedClass(Produto.class);
conf.addAnnotatedClass(Categoria.class);
// gera o esquema do banco
new SchemaExport(conf).create(true, true);
}
}
2) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Adicionar um produto com categoria
Que tal adicionar um Produto que possua uma Categoria? Podemos fazer isso
facilmente com o Hibernate, usando o método save na session().
Mas antes, lembre de alterar a nossa classe HibernateFactory para também
incluir a configuração da classe Categoria, assim como fizemos no GeraTabelas. A
classe HibernateFactory no final ficará assim:
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateFactory {
private static SessionFactory factory;
static {
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.addAnnotatedClass(Produto.class);
cfg.addAnnotatedClass(Categoria.class);
factory = cfg.buildSessionFactory();
}
public Session getSession() {
return factory.openSession();
}
}
Para adicionarmos um Produto com alguma Categoria, primeiro criamos uma
Categoria:
Categoria c = new Categoria();
c.setNome("Uma categoria");
E criamos um Produto:
Produto p = new Produto();
p.setNome("Nome do produto");
p.setDescricao("Sua descricao");
p.setPreco(123.00);
Como dizer agora que o Produto p é da Catgoria c? Basta chamar o setCategoria!
p.setCategoria(c);
Apenas isso! Agora basta obtermos a session, abrirmos uma transação,
salvarmos a categoria e depois salvarmos o produto. Só isso!
Session session = new HibernateFactory().getSession();
Transaction transaction = session.beginTransaction();
session.save(c);
session.save(p);
transaction.commit();
session.close();
Exercício
1) Crie uma classe AdicionaProdutoComCategoria:
Vá em File -> New -> Class
Coloque o pacote como br.com.caelum.hibernate
E o nome da classe como AdicionaProdutoComCategoria
2) Crie o método main e implemente o código visto acima:
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class AdicionaProdutoComCategoria {
public static void main(String[] args) {
Categoria c = new Categoria();
c.setNome("Uma categoria");
Produto p = new Produto();
p.setNome("Nome do produto");
p.setDescricao("Sua descricao");
p.setPreco(123.00);
p.setCategoria(c);
Session session = new HibernateFactory().getSession();
Transaction transaction = session.beginTransaction();
session.save(c);
session.save(p);
transaction.commit();
session.close();
}
}
3) Rode a classe e observe o SQL gerado pelo Hibernate:
- Clique com o botão direito na classe e vá em: Run as -> Java Application
Adicional: lista os produtos e sua categoria
Como fazer agora a listagem de produtos listar também o nome da categoria do
produto? Joins? Com hibernate, basta acessarmos no produto, o getCategoria() e
depois o getNome():
p.getCategoria().getNome()
Sem complicação! O Hibernate se vira com o join que precisar fazer. Na nossa
classe ListaProdutos bastaria alterar o for para imprimir o nome da categoria também,
só isso! Veja o código completo do ListaProdutos após a modificação (note que a única
modificação necessária está em amarelo):
package br.com.caelum.hibernate;
import java.util.List;
import org.hibernate.Session;
public class ListaProdutos {
public static void main(String[] args) {
Session session = new HibernateFactory().getSession();
// obtém lista de todos os produtos
List<Produto> produtos = session.createCriteria(Produto.class).list();
// percorre os produtos e imprime o nome de cada um
for (Produto p : produtos) {
System.out.println(
p.getNome() + ", categoria: " + p.getCategoria().getNome());
}
session.close();
}
}
Adicional: Exercícios para o preguiçoso
1-) Teste um programa que faz somente o seguinte: busca um produto por id. O
código deve somente buscar o produto e não imprimir nada! Qual o resultado?
Session session = new HibernateFactory().getSession();
Produto encontrado = (Produto) session.load(Produto.class,new Long(1));
2-) Tente imprimir o nome do produto do teste anterior, o que acontece?
Session session = new HibernateFactory().getSession();
Produto encontrado = (Produto) session.load(Produto.class,new Long(1));
System.out.println(encontrado.getNome());
3-) Antes de imprimir o nome do produto, tente imprmir uma mensagem
qualquer, do tipo: “O select já foi feito”. E agora? Como isso é possível?
Session session = new HibernateFactory().getSession();
Produto encontrado = (Produto) session.load(Produto.class,new Long(1));
System.out.println(“O select já foi feito”);
System.out.println(encontrado.getNome());
Então, onde está o código do select? Ele deve estar no método getNome(), certo?
4-) Imprima o nome da classe do objeto referenciado pela variável encontrado:
Session session = new HibernateFactory().getSession();
Produto encontrado = (Produto) session.load(Produto.class,new Long(1));
System.out.println(“O select já foi feito”);
System.out.println(encontrado.getNome());
System.out.println(encontrado.getClass().getName());
O Hibernate retorna um objeto cujo tipo estende Produto: ele não deixa de ser
um Produto mas não é somente um Produto.
O método getNome() foi sobrescrito nessa classe para fazer a busca na primeira
vez que é chamado, economizando tempo de processamento.
É claro que para fazer o fine-tuning do Hibernate é interessante conhecer muito
mais a fundo o que o Hibernate faz e como ele faz isso.
Adicional: Fazer paginação
Usando a classe ListaProdutos temos a lista com todos os produtos no banco de
dados. Em um sistema com listagens longas, normalmente apresentamos a lista por
páginas. Para implementar paginação, precisamos determinar que a listagem deve
começar em um determinado ponto e ser de um determinado tamanho.
Usando o Criteria, como anteriormente, isso é bastante simples. Podemos fazer o
seguinte:
List<Produto> produtos = session.createCriteria(Produto.class)
.setFirstResult(0).setMaxResults(2).list();
O método setMaxResults determina o tamanho da lista (resultados por página) e
o método setFirstResult determina em que ponto a listagem deve ter início. Por fim,
basta chamar o método list() e a listagem devolvida será apenas daquela página!
No nosso caso estamos listando a partir do primeiro mas apenas 2 resultados.
Adicional: Atualiza (UPDATE)
Assim como save e delete, podemos fazer o update chamando o método update()
na session e passando o produto a ser atualizado. Lembre que, para um update no
banco, além dos dados normais, precisamos do id. O código final, com controle de
transações fica:
package br.com.caelum.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class AtualizaProduto {
public static void main(String[] args) {
// cria um Produto
Produto p = new Produto();
p.setId(1L); // lembre que id é um Long!
p.setNome("Novo nome");
p.setDescricao("Nova descricao");
p.setPreco(78.50);
// obtém sessão
Session session = new HibernateFactory().getSession();
// abre transação
Transaction transaction = session.beginTransaction();
// atualiza o produto
session.update(p);
// comita a transação
transaction.commit();
session.close();
}
}
Download