Escolar Documentos
Profissional Documentos
Cultura Documentos
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 anotaes para facilitar o mapeamento de classes para tabelas - criar classes de dao bem simples utilizando o hibernate - utilizar relacionamentos entre tabelas
Introduo
A utilizao de cdigo SQL dentro de uma aplicao agrava o problema da independncia 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 cdigo SQL da nossa aplicao e permite escolher o tipo de banco de dados enquanto o programa est rodando, permitindo mudar sua base sem alterar nada no seu cdigo Java. Alm disso, ele permite criar suas tabelas do banco de dados de um jeito bem simples, no se fazendo necessrio 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 ao padro tomado pelo Hibernate no satisfaz as necessidades da empresa (como o uso de select *, joins etc), ele possui dezenas de otimizaes 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 corporao Red Hat.
para fazer o mapeamento objeto relacional. Essa API desacoplada da API dos EJBs, fazendo com que a API no precise de um container Java EE para ser utilizado. Gavin King, como um dos lderes 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 lanamento 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 sero javax.persistence e no apenas org.hibernate.
Ambiente usado
Usaremos neste projeto a IDE livre Eclipse (www.eclipse.org) e Java 5. A verso 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 distribudo junto com sua aplicao.
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 so encontrados tambm no site do hibernate e contem outros jars que devemos colocar no nosso projeto.
Exerccio
1) Abra o eclipse e selecione o workspace padro. 2) Crie um novo projeto Java: File -> New -> Project -> Java Project Clique em Next e na prxima 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 boto 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 diretrio lib: - Clique com o boto 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 boto direito e v em: Build Path -> Add to build path...
Propriedades do banco
O arquivo hibernate.properties um arquivo de propriedades para configurarmos as opes do hibernate. H centenas de configuraes possveis, como avanados controles de cache, transaes e outros. Para nosso sistema, precisamos de quatro linhas bsicas, que configuram o banco, o driver, o usurio 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. Alm disso, vamos colocar uma opo 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 aplicao. No nosso caso, basta coloclo no diretrio src. Alm disso, vamos copiar tambm um arquivo chamado log4j.properties para configurar o log do hibernate; usamos o arquivo padro que vem junto com o hibernate.
Exerccios
1-) Para economizarmos tempo, copie o arquivo properties citado acima para dentro do diretrio src de nosso projeto: Clique com o boto 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
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 mtodos de acesso get e set. package br.com.caelum.hibernate; public class Produto { private private private private } Alm de termos a classe modelando a entidade Produto no nosso programa Java, precisamos de alguma forma de persist-lo no banco de dados. Normalmente, criaramos 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. Long id; String nome; String descricao; double preco;
@Id @GeneratedValue private Long id; private String nome; private String descricao; private double preco; } // gets e sets aqui A especificao do EJB3 define tais anotaes e possui diversas opes que podemos utilizar em nosso projeto. Sempre que possuir alguma dvida em relao as anotaes lembre-se de ler a tal especificao. O API comum das anotaes usadas pelo Hibernate e o EJB3 o Java Persistence API, no pacote javax.persistence.
Exerccios
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 atravs da classe AnnotationConfiguration. // cria a configurao do hibernate AnnotationConfiguration conf = new AnnotationConfiguration(); A partir da podemos adicionar quantas classes desejarmos a nossa configurao. // 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 atravs das anotaes do Hibernate. Ao adicionarmos a classe Produto na nossa configurao, o Hibernate l essas configuraes.
XML
Essa configurao poderia ser feita atravs de um arquivo xml chamado hibernate.cfg.xml, e em vez de utilizarmos as chamadas ao mtodo addAnnotatedClass iramos executar o mtodo configure() .
Criando as tabelas
SCHEMA EXPORT
Vamos criar um programa que gera as tabelas do banco. Dada uma configurao, a classe SchemaExport capaz de gerar o cdigo DDL de criao de tabelas em determinado banco (no nosso caso, o hsqldb). Para exportar tais tabelas, fazemos uso do mtodo create que recebe dois argumentos booleanos. O primeiro diz se desejamos ver o cdigo DDL e o segundo se desejamos execut-lo realmente. // gera a tabela no banco new SchemaExport(conf).create(true, true); O cdigo final da classe GeraTabelas, incluindo a configurao, voc v no exerccio abaixo:
Exerccios
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 mtodo main e, dentro dele, faa a configurao 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 configurao 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 cdigo anterior. Clique com o boto direito no nome da classe, v em: Run As... -> Java Application O Hibernate deve reclamar que no configuramos nenhum arquivo de log para ele (dois warnings, ignore-os) e mostrar o cdigo SQL que ele executou no banco.
Sesses
O hibernate np te d acesso direto s conexes com o banco de dados. Ele trabalha com a idia de sesses de uso do banco. Para efetuar alguma operao no banco (INSERT, SELECT, ...) voc precisa, antes, obter uma sesso do hibernate. O Hibernate prov uma fbrica de sesses, onde voc pode obter uma sesso quando quiser. Na configurao do hibernate, chamamos o mtodo buildSessionFactory() que nos devolve uma SessionFactory. SessionFactory factory = conf.buildSessionFactory(); factory.close(); O Hibernate gera sesses atravs dessa factory. Essas sesses so responsveis por se conectar ao banco de dados e persistir e buscar objetos no mesmo. A maneira mais simples de abrir uma nova sesso e fechar a mesma : Session session = factory.openSession(); session.close();
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 esttico das linhas 4 a 8 cuidar de configurar o Hibernate e pegar uma SessionFactory. Lembre-se que o bloco esttico executado automaticamente quando a classe carregada pelo Class Loader e s neste momento; ele no ser executado outras vezes, como quando voc der new HibernateFactory(). Ou seja, a configurao do Hibernate ser feita uma nica vez em todo seu programa. O mtodo getSession SessionFactory do Hibernate. devolver uma Session, conseguida atravs do
Exerccios
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 seo anterior. No momento de importar Session lembre-se que no 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(); }
Erros comuns
1-) O erro mais comum ao criar a classe HibernateFactory est em importar org.hibernate.classic.Session ao invs de org.hibernate.Session. Uma vez que o mtodo openSession devolve uma Session que no do tipo classic, o Eclipse pede para fazer um casting. No faa o casting! Remova o seu import e adicione o import correto.
Exerccios
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 mtodo 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("Descrio aqui"); p.setPreco(100.50); // obtm uma sesso Session session = new HibernateFactory().getSession(); // Inicia uma transao Transaction transaction = session.beginTransaction(); // salva o produto session.save(p); // Comita a transao transaction.commit(); // veja o id gerado System.out.println("ID do produto: " + p.getId()); session.close(); } } 3-) Adicione um produto executando o cdigo anterior. Clique com o boto direito no nome da classe, v em: Run As... -> Java Application O Hibernate deve mostrar o cdigo 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 primria, no caso o seu id, utilizamos o mtodo load, conforme o exemplo a seguir: // procura o produto de id 2 Produto p = (Produto) session.load(Produto.class, 1L);
Exerccio
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 mtodo 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) { // obtm uma sesso 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()); } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application session.close();
Exerccio
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 mtodo 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(); // obtm 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()); } } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application session.close();
Exerccio
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 mtodo 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(); // obtm 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 boto direito na classe e v em: Run as -> Java Application
Remoo (DELETE)
Assim como inserir usando o Hibernate muito simples, remover tambm bastante simples. Basta chamarmos o mtodo 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 algum precisamos dizer qual o id dele. Ento nosso Produto precisa estar com o id setado. No se esquea tambm que precisamos de uma Transaction para executar algo no banco. O cdigo final fica: // cria um Produto e seta seu id Produto p = new Produto(); p.setId(0L); // lembre que id um Long! // obtm sesso Session session = new HibernateFactory().getSession();
// abre transao Transaction transaction = session.beginTransaction(); // apaga o produto session.delete(p); // comita a transao transaction.commit(); session.close();
Exerccio
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 mtodo 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! // obtm sesso Session session = new HibernateFactory().getSession(); // abre transao Transaction transaction = session.beginTransaction(); // apaga o produto session.delete(p); // comita a transao transaction.commit(); session.close(); } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto 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 fcil criar relacionamentos
entre entidades. Comeamos criando uma classe para representar uma Categoria com, por exemplo, id e nome. Como ela uma classe a ser gerenciada pelo Hibernate, marcamos as anotaes 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.
Exerccio
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;
- Selecione os atributos da classe e v em: - Source -> Generate Getters and Setters - Clique em Select All e depois em Finish.
@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
Exerccio
1) Abra sua classe Produto. Acrescente um atributo do tipo Categoria chamado categoria. Marque esse atributo com a anotao @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 cdigo 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 configurao, que agora temos, alm de Produto, tambm Categoria: // cria a configurao 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);
Exerccio
1) Abra sua classe GeraTabelas. Logo depois de adicionar o Produto configurao, adicione a Categoria tambm. O cdigo 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 configurao 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 boto direito na classe e v em: Run as -> Java Application
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 transao, 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();
Exerccio
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 mtodo main e implemente o cdigo 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 boto direito na classe e v em: Run as -> Java Application
3-) Antes de imprimir o nome do produto, tente imprmir uma mensagem qualquer, do tipo: O select j foi feito. E agora? Como isso possvel?
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());
Ento, onde est o cdigo do select? Ele deve estar no mtodo getNome(), certo? 4-) Imprima o nome da classe do objeto referenciado pela varivel 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 no deixa de ser um Produto mas no somente um Produto. O mtodo 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.
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); // obtm sesso Session session = new HibernateFactory().getSession(); // abre transao Transaction transaction = session.beginTransaction(); // atualiza o produto session.update(p); // comita a transao transaction.commit(); session.close(); } }