Utilizando Swing com Hibernate (SessionFactory)
Este tutorial segue a série de tutoriais Utilizando Swing com Banco de Dados e Utilizando Swing com JPA/Hibernate. Continuaremos utilizando o framework Hibernate, para a persistência com banco de dados, mas desta vez ao invés de utilizarmos objetos EntityManager
da especificação JPA, iremos utilizar a SessionFactory
do Hibernate.
Utilizaremos desta vez o banco de dados Derby no modo Standalone, mas quem preferir pode utilizar o MySql ou outro banco de dados de sua preferência, é só lembrar de alterar os dados para conexão no arquivo de configuração e adicionar o drive JDBC no projeto..
O padrão MVC também será seguido, então caso não tenha lido os tutoriais anteriores, seria importante ler a respeito do que é o padrão MVC.
1. Arquivos necessários
Para o desenvolvimento deste tutorial serão necessárias algumas bibliotecas referentes ao Hibernate e a JPA, e mais algumas que necessitam ser utilizadas como algumas dependências. E também é claro do Driver JDBC do Derby que pode ser baixado aqui: http://db.apache.org/derby/derby_downloads.html. No tutorial estou utilizando a versão 10.7.1.1, então baixe o arquivo db-derby-10.7.1.1-bin.zip.
Veja as bibliotecas necessárias na figura 1.
Montei um pacote com todas as bibliotecas e as disponibilizei para download aqui, adicione a elas o driver JDBC do Derby.
2. Hibernate e a SessionFactory
A SessionFactory
é uma interface do próprio Hibernate, seria uma fabrica de sessões onde teremos uma única SessionFactory
e várias Session’s. Podemos configurar uma SessionFactory
através de três formas, programaticamente, ou através de um arquivo do tipo Properties e por último um arquivo do tipo XML, o qual será usado neste tutorial.
Quando todos os mapeamentos forem analisados pelo org.hibernate.cfg.Configuration
, a aplicação deve obter uma factory para as instancias do org.hibernate.Session
. Veremos isso mais a frente.
3. Arquivo hibernate.cfg.xml
Quando utilizamos o Hibernate precisamos configurar o framework com informações para seu uso. Como já foi citado na sessão 2, utilizaremos estas configurações através de um arquivo XML, nomeado como hibernate.cfg.xml
.
O Hibernate por padrão procura por esse arquivo no classpath
da aplicação, então iremos criá-lo no seguinte diretório, veja na figura 2.
Como iremos criar um banco de dados Derby no modo standalone, precisamos adicionar na propriedade hibernate.connection.url
um comando que irá dizer ao Derby que vamos criar o banco em tempo de execução. Esse comando é, create=true
, como veremos na listagem 1. Após a criação do banco de dados é aconselhavél setar essa configuração para false
.
Desta vez então, não iremos criar uma classe para a geração do banco de dados, como foi feito no tutorial anterior Utilizando Swing com JPA/Hibernate.
O banco de dados quando criado, criará um diretório chamado agenda e dentro deste diretório será criado todos os arquivos utilizados pelo Derby referente a base de dados. Para ver onde será criado este diretório, veja na figura 2, acima do diretório lib
. Não é necessário você criar o diretório agenda
, ele será criado automaticamente quando a aplicação for executada.
Todas as configurações devem ser adicionadas dentro da tag
, inclusive o local onde se encontra o mapeamento das tabelas, no nosso caso a classe que contém as anotações referentes a tabela Contatos
.
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.DerbyDialect </property> <property name="hibernate.connection.url"> jdbc:derby:agenda;create=true </property> <property name="hibernate.connection.driver_class"> org.apache.derby.jdbc.EmbeddedDriver </property> <property name="hibernate.connection.username"> derby </property> <property name="hibernate.connection.password"> derby </property> <property name="hibernate.format_sql"> true </property> <property name="hibernate.show_sql"> true </property> <property name="hibernate.use_sql_comments"> false </property> <!-- Disable the second-level cache --> <property name="hibernate.cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <!-- DB schema will be updated if needed --> <property name="hbm2ddl.auto"> update </property> <property name="hibernate.current_session_context_class"> thread </property> <!-- mapeamentos --> <mapping class="br.mb.tutorialHibernate.model.Contato"/> </session-factory> </hibernate-configuration>
4. Tabela contatos
A tabela Contatos
será criada pelo próprio Hibernate através das anotações e da configuração no arquivo hibernate.cfg.xml
. O que indica ao hibernate que ele deve criar o banco de dados é a propriedade hbm2dll.auto
.
Quando setada como create ela cria o banco novamente sempre que iniciamos a aplicação, quando setada como update
ele ira criar na primeira vez, e apenas atualizar o banco de dados caso seja criada uma nova classe com mapeamento de outra tabela, mas tome cuidado, algumas vezes o Hibernate acaba apagando os dados das tabelas já existentes quando utilizamos o update
.
Se essa geração as vezes não funciona para alguns bancos de dados, então irei disponibilizar na listagem 2 uma classe para geração do banco de dados, algo semelhante ao que foi feito no tutorial de JPA/Hibernate.
package br.mb.tutorialHibernate.agenda; import br.mb.tutorialHibernate.model.Contato; import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport; public class GeraBanco { public static void main(String args[]) { //adicionar no addClass a classe que // ira criar ou alterar a tabela Configuration configuration = new Configuration() .addAnnotatedClass(Contato.class); // carrega as configurações do seu hibernate.cfg.xml configuration.configure(); SchemaExport se = new SchemaExport(configuration); se.create(true, true); // aqui o primeiro true gera o script de criação do banco, // o segundo se voce quer executar ele no banco ou não } }
Quem utilizar um banco de dados no modo servidor, como o Mysql ou outros, algumas vezes será necessário criar o banco de dados manualmente no gerenciador, para então o Hibernate criar as tabelas.
5. Classe de Conexão
Nossa classe de conexão agora trabalhará com SessionFactory
e não EntityManager
, como pode ser visto na listagem 3.
package br.mb.tutorialHibernate.dao; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static SessionFactory SESSION_FACTORY; static { try { // Create the SessionFactory from hibernate.cfg.xml SESSION_FACTORY = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static Session getSession() { return SESSION_FACTORY.openSession(); } }
Será criada uma SessionFactory
através do objeto Configuration
e será criado um método getSession()
, onde abrimos uma sessão através SessionFactory
. Uma sessão será aberta sempre que tivermos uma interação com o banco de dados.
6. Classe GenericDao
Vamos criar uma classe genérica para os métodos insert, update e delete, e algumas consultas que podem ser padrão para várias entidades, veja na listagem 4.
package br.mb.tutorialHibernate.dao; import org.hibernate.Session; import org.hibernate.criterion.Restrictions; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.util.List; public class GenericDao{ private final Session session; private final Class persistentClass; public GenericDao() { this.session = HibernateUtil.getSession(); this.persistentClass = (Class ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } public Session getSession() { return session; } protected void save(T entity) { try { getSession().getTransaction().begin(); getSession().save(entity); getSession().getTransaction().commit(); } catch (Throwable t) { getSession().getTransaction().rollback(); t.printStackTrace(); } finally { close(); } } protected void update(T entity) { try { getSession().getTransaction().begin(); getSession().update(entity); getSession().getTransaction().commit(); } catch (Throwable t) { getSession().getTransaction().rollback(); t.printStackTrace(); } finally { close(); } } protected void delete(T entity) { try { getSession().getTransaction().begin(); getSession().delete(entity); getSession().getTransaction().commit(); } catch (Throwable t) { getSession().getTransaction().rollback(); t.printStackTrace(); } finally { close(); } } public List findAll() throws Exception { return getSession().createCriteria(persistentClass).list(); } public T findByName(String nome) { return (T) getSession().createCriteria(persistentClass) .add(Restrictions.eq("nome", nome).ignoreCase()).uniqueResult(); } public T findById(long id) { return (T) getSession().createCriteria(persistentClass) .add(Restrictions.eq("id", id)).uniqueResult(); } private void close() { if (getSession() != null && getSession().isOpen()) { getSession().close(); } } }
No construtor da classe criamos um objeto Session
, que nos dará acesso aos métodos necessários, e obtemos a entidade que está utilizando a classe no momento.
Nos métodos save()
, update()
e delete()
, precisamos criar uma transação, abrir está transação e então executar o que queremos fazer. No caso do método save()
, utilizamos o save()
, que recebe como par metro um objeto e o framework executa um insert através dele. A grande vantagem é que não precisamos nos preocupar com o SQL de insert, update ou delete, só passamos o objeto e o framework faz o resto.
Depois da execução, se tudo ocorrer bem é executado um commit na transação do banco de dados e então um close é chamado para fechar a comunicação com o banco de dados.
Nas consultas foi utilizada a API Criteria, uma forma diferente de fazer o “select” quando utilizamos orientação objetos e não objetos relacionais. Outra forma que pode ser utilizada é o HQL, um dialeto SQL para o Hibernate, uma consulta muito parecida com o SQL, porém se trabalha com objetos e seus atributos e não com tabelas e colunas.
Quando utilizamos Criteria, precisamos indicar qual a entidade que fará a consulta, por isso, utilizamos a variável persistentClass
, para passarmos para o método qual entidade está sendo executada no momento da consulta. Seria como se ele estivesse passando por parametro algo como isto: Contato.class
O objeto session
, através do método getSession()
, pode também nos fornecer o método de persistência saveOrUpdate(entity)
. Este método executa por conta um update ou um insert, dependendo do que estiver sendo passado para ele por par metro. Se a entidade passada já contiver um ID
diferente de null
, então ele executa um update, caso a entidade tenha um ID
igual null
, ele então cria uma nova linha na tabela como se executasse o método save()
.
7. Classe Contato
Nossa classe Contato
terá como atributos os campos da tabela Contatos
, mapeados em forma de anotações. Através das anotações podemos passar todas as informações que uma coluna teria como o tipo de dado, tamanho, nome, entre outros.
Essa classe pode ser obtida no tutorial anterior Utilizando Swing com JPA/Hibernate. Mude apenas o nome do pacote para package br.mb.tutorialHibernate.model;
.
8. Classe ContatoDao
Criamos a classe GenericDao
para ser herdadas pelos demais DAO’s, assim, vamos agora criar a classe ContatoDao
, onde estarão os métodos mais específicos da classe.
Essa classe pode ser obtida no tutorial anterior Utilizando Swing com JPA/Hibernate. Mude o nome do pacote para package br.mb.tutorialHibernate.dao;
e importe a classe Contato
do pacote correspondente a este projeto.
9. Classe ContatoController
Nenhuma alteração será feita na classe controller em relação a métodos, então você pode utilizar a classe do artigo anterior, essa classe pode ser obtida no tutorial Utilizando Swing com JPA/Hibernate. Mude apenas o nome do pacote para package br.mb.tutorialHibernate.controller;
e importe a classe Contato
e ContatoDao
correspondentes a esse projeto.
10. Classe ContatoFrame
A interface continua a mesma, uma interface como a da figura 3.
Esta classe não foi postada no artigo, mas você pode pegá-la no tutorial anterior, acessando Utilizando Swing com JPA/Hibernate, e é claro, não se esqueça de alterar o nome do pacote e dos imports de ContatoController
e Contato
.
Conclusão
Este tutorial demonstrou como configurar e criar um projeto utilizando Hibernate com o uso da SessionFactory
e banco de dados Derby no modo standalone.
Saiba mais
- Criteria http://download.oracle.com/javaee/6/tutorial/doc/gjitv.html
- Genéricos em Java http://en.wikipedia.org/wiki/Generics_in_Java
- HQL http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html
- Criteria com hibernate http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html
- Documentação de Referência Hibernate http://docs.jboss.org/hibernate/core/3.5/reference/pt-BR/pdf/hibernate_reference.pdf
- Hibernate Annotations http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html
- Graphical User Interface http://download.oracle.com/javase/tutorial/ui/index.html