Open Session View – Hibernate Solução

solutionproblem

olá Pessoal,

No post de hoje vou falar de um problema que todos que estão trabalhando com Hibernate não está livre de se deparar com ele. É o velho LazyInitializationException que acontece e deixa o pobre do desenvolvedor stressado.

Neste post pretendo ser menos teórico e mais prático, pois tem muita coisa na net explicando o porque temos o LazyInitializationException, porém poucos explicaram de forma prática a solução. O mais próximo foi este site. Que se você reparar direito tem um pequeno erro no mapeamento do filtro.

Então aqui vou mostrar como resolver o problema, pois também fui afetado com este problema e levei umas quase 3 horas para resolver. E agora vejo que era algo simples, mas eu precisava entender o por que?! de cada exceção que vinha recebendo. Para este este post usei o post que está no Jboss Community, porém fiz algumas adaptações.

Lets go…

Vou usar a técnica de reutilização da informação então o Paulo da Caelum já fez uma abordagem excelente do porque desse problema , veja.

Desenvolvendo

Se você não quer desenvolver os codes a seguir, então mude o relacionamento para EAGER ao invés de usar o LAZY. Os codes a seguir é útil para quem necessita de ser LAZY o relacionamento.

  1. crie um novo package no seu projeto o meu chamei de : br.com.filtro

O pessoal do Jboss Community não colocou quais classes deveriamos importar, um programador inexperiente pode se atrapalhar e importar classes inapropriadas. Em função disso coloquei abaixo o código completo.

  1. Crie a classe HibernateSessionRequestFilter conforme abaixo: (fique atento ao meu comentário na classe)

    package br.com.filtro;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.hibernate.SessionFactory;
    import org.hibernate.StaleObjectStateException;
    
    import br.com.dao.DAO;
    
    public class HibernateSessionRequestFilter implements Filter {
    
    	 private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);
    
    	    private SessionFactory sf;
    
    	    public void doFilter(ServletRequest request,
    	                         ServletResponse response,
    	                         FilterChain chain)
    	            throws IOException, ServletException {
    
    	        try {
    	          System.out.println("iniciando a transacao com o DB");
    	            sf.getCurrentSession().beginTransaction();
    
    	            // Call the next filter (continue request processing)
    	            chain.doFilter(request, response);
    
    	            // Commit and cleanup
    	            log.debug("Committing the database transaction");
    	          sf.getCurrentSession().getTransaction().commit();
    
    	        } catch (StaleObjectStateException staleEx) {
    	            log.error("This interceptor does not implement optimistic concurrency control!");
    	            log.error("Your application will not work until you add compensation actions!");
    	            // Rollback, close everything, possibly compensate for any permanent changes
    	            // during the conversation, and finally restart business conversation. Maybe
    	            // give the user of the application a chance to merge some of his work with
    	            // fresh data... what you do here depends on your applications design.
    	            throw staleEx;
    	        } catch (Throwable ex) {
    	            // Rollback only
    	            ex.printStackTrace();
    	            try {
    	                if (sf.getCurrentSession().getTransaction().isActive()) {
    	                    log.debug("Trying to rollback database transaction after exception");
    	                    sf.getCurrentSession().getTransaction().rollback();
    	                }
    	            } catch (Throwable rbEx) {
    	                log.error("Could not rollback transaction after exception!", rbEx);
    	            }
    
    	            // Let others handle it... maybe another interceptor for exceptions?
    	            throw new ServletException(ex);
    	        }
    	    }
    
    	    public void init(FilterConfig filterConfig) throws ServletException {
    	        //log.debug("Initializing filter...");
    	       // log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
    	        sf = DAO.getSessionFactory();//vem da minha classe DAO
    	    }
    
    	    public void destroy() {}
    
    }
  2. Agora veja como está meu DAO:

    package br.com.dao;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class DAO {
    	private static ThreadLocal threadlocal = new ThreadLocal();
    	private static SessionFactory sessionFactory = new Configuration().configure().
    	buildSessionFactory(); 
    
    public DAO() {
    	// TODO Auto-generated constructor stub
    }
    public static  Session getSession(){
    	Session session = (Session) threadlocal.get();
    	if(session == null){
    		session = sessionFactory.openSession();
    		threadlocal.set(session);
    	}
    	return session;
    }
    	public void begin(){
    		getSession().beginTransaction();
    
    	}
    public void commit(){
    	getSession().getTransaction().commit();
    }
    
    public void rollback(){
    	getSession().getTransaction().rollback();
    }
    public void close(){
    	getSession().close();
    }
    public static void shutdown() {
    	// Close caches and connection pools
    	getSessionFactory().close();
    	}
    //passamos ele para o Filter
    public static SessionFactory getSessionFactory() {
    	return sessionFactory;
    }
    public static void setSessionFactory(SessionFactory sessionFactory) {
    	DAO.sessionFactory = sessionFactory;
    }
    
    }

Não precisei alterar nada da configuração padrão do hibernate.

  1. Abra seu arquivo hibernate.cfg.xml e adicione a linha abaixo:

    < property name=”hibernate.current_session_context_class”>thread  < /property>

  2. Salve e execute sua aplicação, veja se os println do Filter serão impressos (claro, os que estão nos catches nem devem aparecer). Em caso positivo está tudo ok.

  3. Agora teste várias vezes sua app e veja se verá o problema com LazyInitializationException. Aqui ele sumiu de vez, graças à deus.

A única coisa que mudei na classe HibernateSessionRequestFilter, foi informar meu SessionFactory e o resto o Filter fez o trabalho dele.

Bom vou ficando por aqui, espero que tenham gostado do post. Não posso deixar de agradecer ao autor Edson Gonçalves que contribuiu bastante para este post, desde a indicação do link, como as explanações pelo mesmo que foi contribuindo  até encontrar a solução, o colega Rafael Viana (GUJ) já tinha passado por um problema parecido e compartilhou sua experiência opinando como poderia ser resolvido.

Fica ai agora a versão em português do problema. Abracos, see you next post.