Utilizando um pool de conexões com hibernate
Autor: Cristiano Pires | Publicado: 2011-11-29T10:56:00-02:00


Parece algo já muito falado na web. Mas o que vou tratar aqui nem todo mundo usa e as vezes sofre com certos tipos de erros.

O caso descrito é o seguinte: 
Tenho um número X de agências bancárias do banco Y. E tenho que controlar as linhas telefônicas do banco.
Cada cidade tem N agências com N telefones cada. E cada agência pode ter posto de auto atendimento em outros locais. Cada posto de auto atendimento tem uma agência que é responsável por ele. Preciso saber quais são os terminais telefônicos de cada agência.

Trataremos da seguinte forma. O sistema será implementado quando as agências e suas linhas telefônicas já estão em funcionamento. Então teremos um banco de dados legado.

Vou criar um DAO genérico do tipo que tem muito tutorial por aí, depois vamos aperfeiçoar.


A vantagem do DAO genérico é que ele pode ser utilizado para executar operações persistentes de qualquer entidade. 



primeiro, criamos a interface GenericDAO




import&nbsp;java.io.Serializable;

import&nbsp;java.util.List;



import&nbsp;org.hibernate.Session;





public&nbsp;interface&nbsp;GenericDAO&lt;T&gt;&nbsp;{

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;Session&nbsp;getSession();

&nbsp;&nbsp;public&nbsp;T&nbsp;getById(Serializable&nbsp;id);

&nbsp;&nbsp;public&nbsp;List&lt;T&gt;&nbsp;getAll();

&nbsp;&nbsp;public&nbsp;T&nbsp;save(T&nbsp;entity);

&nbsp;&nbsp;public&nbsp;void&nbsp;delete(T&nbsp;entity);



}


&nbsp; 



Agora a classe que implementa a interface que acabamos de criar


import&nbsp;java.io.Serializable;
import&nbsp;java.lang.reflect.ParameterizedType;
import&nbsp;java.util.List;

import&nbsp;org.hibernate.Session;

import&nbsp;telefonia.dao.GenericDAO;

public&nbsp;abstract&nbsp;class&nbsp;HibernateGenericDao&lt;T&gt;&nbsp;implements&nbsp;GenericDAO&lt;T&gt;&nbsp;{

&nbsp;&nbsp;private&nbsp;Class&lt;T&gt;&nbsp;persistentClass;
&nbsp;&nbsp;private&nbsp;Session&nbsp;session;
&nbsp;&nbsp;
&nbsp;&nbsp;@SuppressWarnings("unchecked")
&nbsp;&nbsp;public&nbsp;HibernateGenericDao(Session&nbsp;session)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;this.session&nbsp;=&nbsp;session;
&nbsp;&nbsp;&nbsp;&nbsp;this.persistentClass&nbsp;=&nbsp;(Class&lt;T&gt;)&nbsp;((ParameterizedType)getClass().getGenericSuperclass()).
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getActualTypeArguments()[0];
&nbsp;&nbsp;}
&nbsp;&nbsp;
&nbsp;&nbsp;@Override
&nbsp;&nbsp;public&nbsp;Session&nbsp;getSession()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.session;
&nbsp;&nbsp;}

&nbsp;&nbsp;@SuppressWarnings("unchecked")
&nbsp;&nbsp;@Override
&nbsp;&nbsp;public&nbsp;T&nbsp;getById(Serializable&nbsp;id)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(T)this.session.get(this.persistentClass,&nbsp;id);
&nbsp;&nbsp;}

&nbsp;&nbsp;@SuppressWarnings("unchecked")
&nbsp;&nbsp;@Override
&nbsp;&nbsp;public&nbsp;List&lt;T&gt;&nbsp;getAll()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.session.createCriteria(this.persistentClass).list();
&nbsp;&nbsp;}

&nbsp;&nbsp;@SuppressWarnings("unchecked")
&nbsp;&nbsp;@Override
&nbsp;&nbsp;public&nbsp;T&nbsp;save(T&nbsp;entity)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(T)this.session.merge(entity);
&nbsp;&nbsp;}

&nbsp;&nbsp;@Override
&nbsp;&nbsp;public&nbsp;void&nbsp;delete(T&nbsp;entity)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;this.session.delete(entity);
&nbsp;&nbsp;}
}




A classe terminal, que representa cada terminal ou linha telefônica.


@Entity

@Table&nbsp;(name="terminal")&nbsp;&nbsp;

public&nbsp;class&nbsp;Terminal&nbsp;implements&nbsp;Serializable&nbsp;{

&nbsp;&nbsp;

&nbsp;&nbsp;private&nbsp;static&nbsp;final&nbsp;long&nbsp;serialVersionUID&nbsp;=&nbsp;1L;

&nbsp;&nbsp;

&nbsp;&nbsp;private&nbsp;Long&nbsp;id;

&nbsp;&nbsp;private&nbsp;Prefixo&nbsp;idPrefixo;

&nbsp;&nbsp;private&nbsp;Operadora&nbsp;idOperadora;

&nbsp;&nbsp;private&nbsp;Integer&nbsp;ddd;

&nbsp;&nbsp;private&nbsp;Integer&nbsp;numero;

&nbsp;&nbsp;private&nbsp;Date&nbsp;dataInstalacao;

&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;@Id

&nbsp;&nbsp;@GeneratedValue

&nbsp;&nbsp;@Column(name="id_terminal")

&nbsp;&nbsp;public&nbsp;Long&nbsp;getId()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;id;

&nbsp;&nbsp;}

&nbsp;&nbsp;public&nbsp;void&nbsp;setId(Long&nbsp;id)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;this.id&nbsp;=&nbsp;id;

&nbsp;&nbsp;}

&nbsp;&nbsp;

//getters&nbsp;e&nbsp;setters



Agora vamos criar o DAO para a entidade Terminal. 
Essa&nbsp; interface&nbsp; é&nbsp; uma&nbsp; especialização&nbsp; de&nbsp; GenericDAO.&nbsp; Definimos que o tipo da entidade é Terminal, quando herdamos GenericDAO. 


public&nbsp;interface&nbsp;TerminalDao&nbsp;extends&nbsp;GenericDAO&lt;Terminal&gt;&nbsp;{

&nbsp;&nbsp;public&nbsp;List&lt;Terminal&gt;&nbsp;getListaTerminaisPorNumeroDeTelefone(Long&nbsp;telefone);

&nbsp;&nbsp;public&nbsp;Terminal&nbsp;getTerminalPorNumero(Long&nbsp;numero);

}




Vamos criar uma&nbsp; classe&nbsp; chamada&nbsp; HibernateTerminalDAO&nbsp; que&nbsp; herda&nbsp; as&nbsp; implementações 
do&nbsp; DAO&nbsp; genérico&nbsp; para&nbsp; Hibernate&nbsp; (class&nbsp; HibernateGenericDAO)&nbsp; e&nbsp; implementa&nbsp; a&nbsp; interface TerminalDAO, que é uma interface que define métodos genéricos e específicos. 




public&nbsp;class&nbsp;HibernateTerminalDao&nbsp;extends&nbsp;HibernateGenericDao&lt;Terminal&gt;&nbsp;implements&nbsp;TerminalDao&nbsp;{



&nbsp;&nbsp;public&nbsp;HibernateTerminalDao(Session&nbsp;session)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;super(session);

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;List&lt;Terminal&gt;&nbsp;getListaTerminaisPorNumeroDeTelefone(Long&nbsp;telefone)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.getSession().createCriteria(Terminal.class)

&nbsp;&nbsp;&nbsp;&nbsp;.add(Restrictions.eq("numero",&nbsp;telefone.toString().substring(2,&nbsp;telefone.toString().length())))

&nbsp;&nbsp;&nbsp;&nbsp;.add(Restrictions.eq("ddd",&nbsp;Integer.parseInt(telefone.toString().substring(0,&nbsp;2))))

&nbsp;&nbsp;&nbsp;&nbsp;.addOrder(Property.forName("numero").asc())

&nbsp;&nbsp;&nbsp;&nbsp;.list();

&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;Terminal&nbsp;getTerminalPorNumero(Long&nbsp;numero)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(Terminal)&nbsp;this.getSession().createQuery("select&nbsp;t&nbsp;from&nbsp;Terminal&nbsp;t&nbsp;where&nbsp;t.numero&nbsp;=&nbsp;:tnum&nbsp;and&nbsp;t.ddd&nbsp;=&nbsp;:tddd").

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setParameter("tnum",&nbsp;numero.toString().substring(2,&nbsp;numero.toString().length())).

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setParameter("tddd",&nbsp;Integer.parseInt(numero.toString().substring(0,&nbsp;2))).uniqueResult();

&nbsp;&nbsp;&nbsp;&nbsp;}

}



A classe HibernateConnection


public&nbsp;class&nbsp;HibernateConnection&nbsp;{

&nbsp;&nbsp;private&nbsp;static&nbsp;final&nbsp;SessionFactory&nbsp;sessionFactory;



&nbsp;&nbsp;static&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sessionFactory&nbsp;=&nbsp;new&nbsp;AnnotationConfiguration().configure()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.buildSessionFactory();

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Throwable&nbsp;ex)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ExceptionInInitializerError(ex);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;public&nbsp;static&nbsp;Session&nbsp;getSession()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;sessionFactory.openSession();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;session;

&nbsp;&nbsp;}




Agora finalmente vamos criar a tal da fábrica de conexões (DAO)



public&nbsp;abstract&nbsp;class&nbsp;DAOFactory&nbsp;{



&nbsp;&nbsp;public&nbsp;static&nbsp;DAOFactory&nbsp;getDAOFactory()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;HibernateDAOFactory();

&nbsp;&nbsp;}



&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;startTransaction();

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;cancelTransaction();

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;finalize();

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;abstract&nbsp;TerminalDao&nbsp;getTerminalDao();



}



A classe HibernateDAOFactory que implementa os métodos da classe abstrata DAOFactory


public&nbsp;class&nbsp;HibernateDAOFactory&nbsp;extends&nbsp;DAOFactory&nbsp;{&nbsp;



&nbsp;&nbsp;private&nbsp;Session&nbsp;session;&nbsp;

&nbsp;&nbsp;private&nbsp;Transaction&nbsp;tx;&nbsp;

&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;HibernateDAOFactory()&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;this.session&nbsp;=&nbsp;HibernateConnection.getSession();&nbsp;

&nbsp;&nbsp;}

&nbsp;&nbsp;

&nbsp;&nbsp;@Override&nbsp;

&nbsp;&nbsp;public&nbsp;void&nbsp;cancelTransaction()&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;this.tx.rollback();&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;this.tx&nbsp;=&nbsp;null;&nbsp;

&nbsp;&nbsp;}&nbsp;



&nbsp;&nbsp;@Override&nbsp;

&nbsp;&nbsp;public&nbsp;void&nbsp;startTransaction()&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;this.tx&nbsp;=&nbsp;this.session.beginTransaction();&nbsp;

&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;@Override&nbsp;

&nbsp;&nbsp;public&nbsp;void&nbsp;finalize()&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(this.tx&nbsp;!=&nbsp;null)&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.tx.commit();&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;this.session.close();&nbsp;

&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;

&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;TerminalDao&nbsp;getTerminalDao()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;HibernateTerminalDao(this.session);

&nbsp;&nbsp;}

}



Agora para instanciar o DAO, vamos criar os seguintes métodos:


public&nbsp;Terminal&nbsp;getTerminalPorNumero(Long&nbsp;numero)&nbsp;throws&nbsp;DaoException&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;DAOFactory&nbsp;daoFactory&nbsp;=&nbsp;DAOFactory.getDAOFactory();

&nbsp;&nbsp;&nbsp;&nbsp;TerminalDao&nbsp;terminalDao&nbsp;=&nbsp;daoFactory.getTerminalDao();

&nbsp;&nbsp;&nbsp;&nbsp;daoFactory.startTransaction();

&nbsp;&nbsp;&nbsp;&nbsp;Terminal&nbsp;t&nbsp;=&nbsp;terminalDao.getTerminalPorNumero(numero);

&nbsp;&nbsp;&nbsp;&nbsp;daoFactory.finalize();

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;t;

&nbsp;&nbsp;}

&nbsp;&nbsp;

public&nbsp;List&lt;Terminal&gt;&nbsp;getListaTerminaisPorNumeroDeTelefone(Long&nbsp;telefone)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;DAOFactory&nbsp;daoFactory&nbsp;=&nbsp;DAOFactory.getDAOFactory();

&nbsp;&nbsp;&nbsp;&nbsp;TerminalDao&nbsp;terminalDao&nbsp;=&nbsp;daoFactory.getTerminalDao();

&nbsp;&nbsp;&nbsp;&nbsp;daoFactory.startTransaction();

&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Terminal&gt;&nbsp;terminais&nbsp;=&nbsp;terminalDao.getListaTerminaisPorNumeroDeTelefone(telefone);

&nbsp;&nbsp;&nbsp;&nbsp;daoFactory.finalize();

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;terminais;

&nbsp;&nbsp;}


&nbsp;




Ambos os métodos acima irão consultar na base de dados o terminal ou uma lista de terminais (caso haja repetição de um mesmo número com ddd igual para agências diferentes). Observe que nossa base de dados é legada, então esse é um erro que provocarei para explicar melhor essa fábrica de conexão.

Agora finalmente, vamos criar um método que vai verificar se existe números repetidos (mesmo ddd e número de telefone) na base de dados. 



private&nbsp;static&nbsp;Terminal&nbsp;verificaNumeroRepetido(String&nbsp;ddd,&nbsp;String&nbsp;numero)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;num&nbsp;=&nbsp;new&nbsp;Long(ddd.concat(numero));

&nbsp;&nbsp;&nbsp;&nbsp;Terminal&nbsp;terminal&nbsp;=&nbsp;null;

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;terminal&nbsp;=&nbsp;new&nbsp;TerminalService().getTerminalPorNumero(num);

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(NonUniqueResultException&nbsp;nre)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Terminal&gt;&nbsp;listaTerminais&nbsp;=&nbsp;new&nbsp;TerminalService().getListaTerminaisPorNumeroDeTelefone(new&nbsp;Long(ddd.concat(numero)));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//aqui&nbsp;tenho&nbsp;uma&nbsp;relação&nbsp;dos&nbsp;números&nbsp;repetidos.&nbsp;Aí&nbsp;o&nbsp;que&nbsp;eu&nbsp;decido o que faço&nbsp;com&nbsp;eles...

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;terminal;

&nbsp;&nbsp;}





O método acima consulta um terminal da base pelo ddd + número. Até aí tudo bem. Caso haja repetição de ddd e número, pego a lista de números repetidos e decido qualquer coisa a ser feito com eles.&nbsp;

O problema, é que quando pegar um número repetido vai gerar uma excessão do tipo NonUniqueResultException e não vai fechar a conexão, vai manter a conexão aberta.

Suponhamos que no pool de conexões do hibernate foi definido no máximo 10 conexões simultâneas:



&lt;!--&nbsp;Pool&nbsp;de&nbsp;conexoes&nbsp;--&gt;

&lt;property&nbsp;name="hibernate.c3p0.min_size"&gt;2&lt;/property&gt;

&lt;property&nbsp;name="hibernate.c3p0.max_size"&gt;10&lt;/property&gt;



Isso implica que quando 10 usuários utilizarem essa rotina, ou mesmo um usuário repetir 
esse processo 10 vezes, a consulta vai literalmente parar esperando uma das conexões cair para tentar instanciar uma nova conexão, ou seja, o sistema vai parar!
O correto seria fazer o sistema prevenir esse tipo de excessão e não instanciar&nbsp;conexões novas enquanto existirem abertas.

Melhorando a fábrica de conexões

Vamos modificar a classe HibernateConnection. É lá que instanciamos novas conexões


public&nbsp;class&nbsp;HibernateConnection&nbsp;{



&nbsp;&nbsp;private&nbsp;static&nbsp;final&nbsp;SessionFactory&nbsp;sessionFactory;

&nbsp;&nbsp;private&nbsp;static&nbsp;final&nbsp;ThreadLocal&lt;Session&gt;&nbsp;threadSession&nbsp;=&nbsp;new&nbsp;ThreadLocal&lt;Session&gt;();



&nbsp;&nbsp;static&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sessionFactory&nbsp;=&nbsp;new&nbsp;AnnotationConfiguration().configure()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.buildSessionFactory();

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Throwable&nbsp;ex)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ExceptionInInitializerError(ex);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;public&nbsp;static&nbsp;Session&nbsp;getSession()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((threadSession.get()&nbsp;==&nbsp;null)&nbsp;||&nbsp;(!threadSession.get().isOpen()))&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;sessionFactory.openSession();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadSession.set(session);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;session;

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;threadSession.get();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;session;

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;closeSession()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;threadSession.get();

&nbsp;&nbsp;&nbsp;&nbsp;threadSession.set(null);



&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(session&nbsp;!=&nbsp;null)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.close();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;HibernateException(e);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



}





Vejamos as alterações. Agora, quando um usuário instanciar uma nova conexão ela será incluída em uma thread que criamos do tipo Session. Quando ocorrer alguma excessão e a conexão não for fechada, o método getSession() vai verificar se a conexão ainda está na thread. Caso esteja, ela será retornada ao usuário e não vai abrir uma nova conexão com a base de dados. Isso me garante que um mesmo usuário não vai abrir N conexões gerando carga e travando minha base de dados.



Foi incluído ainda um novo método: closeSession() que é que vai ser responsável por fechar a conexão e liberá-la da thread.



A mesma coisa ocorre quando não fechamos uma transação (Transaction). Então vamos melhorar a classe HibernateDAOFactory:




public&nbsp;class&nbsp;HibernateDAOFactory&nbsp;extends&nbsp;DAOFactory&nbsp;{

&nbsp;&nbsp;private&nbsp;Session&nbsp;session;

&nbsp;&nbsp;private&nbsp;ThreadLocal&lt;Transaction&gt;&nbsp;threadTransaction&nbsp;=&nbsp;new&nbsp;ThreadLocal&lt;Transaction&gt;();

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;HibernateDAOFactory()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;startSession();

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;void&nbsp;startTransaction()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;Transaction&nbsp;tx&nbsp;=&nbsp;threadTransaction.get();

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(tx&nbsp;==&nbsp;null)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tx&nbsp;=&nbsp;session.beginTransaction();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTransaction.set(tx);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;HibernateException(e);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;void&nbsp;cancelTransaction()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;Transaction&nbsp;tx&nbsp;=&nbsp;threadTransaction.get();

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((tx&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;!tx.wasCommitted())&nbsp;&amp;&amp;&nbsp;(!tx.wasRolledBack()))&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tx.rollback();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTransaction.set(null);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;HibernateException(e);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;void&nbsp;finalize()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;Transaction&nbsp;tx&nbsp;=&nbsp;threadTransaction.get();

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(tx&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;!tx.wasCommitted()&nbsp;&amp;&amp;&nbsp;!tx.wasRolledBack())&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tx.commit();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadTransaction.set(null);


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 


&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cancelTransaction();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;HibernateException(e);

&nbsp;&nbsp;&nbsp;&nbsp;} finalize {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; closeSession();
&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;TerminalDao&nbsp;getTerminalDao()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;HibernateTerminalDao(this.session);

&nbsp;&nbsp;}

&nbsp;&nbsp;

&nbsp;&nbsp;private&nbsp;void&nbsp;startSession()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(session&nbsp;==&nbsp;null&nbsp;||&nbsp;!session.isOpen())&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session&nbsp;=&nbsp;HibernateConnection.getSession();&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;HibernateException(e);

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;}



&nbsp;&nbsp;@Override

&nbsp;&nbsp;public&nbsp;void&nbsp;closeSession()&nbsp;{
&nbsp; &nbsp; this.session = null;

&nbsp;&nbsp;&nbsp;&nbsp;HibernateConnection.closeSession();

&nbsp;&nbsp;}

}


&nbsp;




Fizemos a mesma coisa com as transações. Incluímos ela em uma thread do tipo Transaction, e quando o usuário for instanciar uma transação, verificaremos se ela já não está aberta.



Por último, uma alteração na classe abstrata DAOFactory, vamos incluir o método closeSession() que foi implementado em HibernateDAOFactory


public&nbsp;abstract&nbsp;class&nbsp;DAOFactory&nbsp;{



&nbsp;&nbsp;public&nbsp;static&nbsp;DAOFactory&nbsp;getDAOFactory()&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;HibernateDAOFactory();

&nbsp;&nbsp;}

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;abstract&nbsp;Session&nbsp;getSession();

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;closeSession();

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;startTransaction();

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;cancelTransaction();

&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;finalize();

&nbsp;&nbsp;

&nbsp;&nbsp;public&nbsp;abstract&nbsp;TerminalDao&nbsp;getTerminalDao();

}





Agora temos concluído nossa fábrica de conexões. O exemplo do terminal das agências foi só um pretexto pra provocar um erro possível e não ter dor de cabeça com abrir e fechar conexões. Melhore de acordo com seu código!

É isso! Até a próxima!