DAO Generico quando fechar sessões

10 respostas
T

Bom dia pessoal,
Estou desenvolvendo um sistema para fins didáticos e estou tendo alguns problemas com o lazy loading e a maneira correta de implementar um DAO com o HIBERNATE.

Criei um DAO generico

public class HibernateDAO<T> {
    private Class<T> classe;
    private Session session;
    
    public HibernateDAO(Class<T> classe)
    {
        this.classe = classe;
    }
    
    public void update(T bean) throws Exception
    {
        Transaction tx = null;
        
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            session.update(bean);            
            tx.commit();            
        }catch(Exception ex)
        {            
            ex.printStackTrace();
            tx.rollback();
            throw ex;
        }finally
        {
            session.close();
        }
    }
    
    public void delete(T bean) throws Exception
    {
        Transaction tx = null;
        
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            session.delete(bean);
            session.flush();
            tx.commit();
            
            
        }catch(Exception ex)
        {            
            ex.printStackTrace();
            tx.rollback();
            throw ex;
        }finally
        {
            session.close();
        }
    }
    
    public T getBean(Serializable codigo)
    {
        T bean = null;
        
        try
        {
            session = HibernateUtil.openSession();
            Transaction tx = (Transaction) session.beginTransaction();
            bean = (T) session.get(classe, codigo);
            tx.commit();
            session.close();
        }catch(Exception e)
        {
            e.printStackTrace();
        }        
        return bean;
    }
    
    
    
    
    public void save(T bean) throws Exception
    {
        
        Transaction tx = null;
        
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            session.save(bean);
            session.flush();
            tx.commit();
            
            
        }catch(Exception ex)
        {            
            ex.printStackTrace();            
            tx.rollback();
            throw ex;
        }finally
        {
            session.close();
        }
    }
    
    public void saveOrUpdate(T bean) throws Exception
    {
        
        Transaction tx = null;
        
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            session.saveOrUpdate(bean);
            session.flush();
            tx.commit();
            
            
        }catch(Exception ex)
        {            
            ex.printStackTrace();            
            tx.rollback();
            throw ex;
        }finally
        {
            session.close();
        }
    }
}

mas quando faço uma consulta e busco uma list obtenho um LazyLoadingException

HibernateDAO<TelaBean> ht = new HibernateDAO<TelaBean>(TelaBean.class);
        TelaBean t = ht.getBean(1);
        t.getPermissoes();

Eu sei que o problema esta quando fecho a sessão e tento buscar a lista

Agora minhas duvidas são:

1 - Qual a maneira correta de implementar esse DAO?.

2 - Quando é a hora correta de se fechar a session?.

Tenho essas duvidas pois estou começando a aprender Hibernate e JPA
Agradeço muito a atenção desde ja!

10 Respostas

rafadelnero

O correto é você injetar seu objeto Session:

Session session; public HibernateDAO(Class<T> classe, Session session) { this.session = session; this.classe = classe; }

E fechá-lo após as transações que você fizer.

T

rafadelnero:
O correto é você injetar seu objeto Session:

Session session; public HibernateDAO(Class<T> classe, Session session) { this.session = session; this.classe = classe; }

E fechá-lo após as transações que você fizer.

Então o correto não seria fechar a session dentro do HibernateDAO?

rafadelnero

tioola:
rafadelnero:
O correto é você injetar seu objeto Session:

Session session; public HibernateDAO(Class<T> classe, Session session) { this.session = session; this.classe = classe; }

E fechá-lo após as transações que você fizer.

Então o correto não seria fechar a session dentro do HibernateDAO?

Não, o correto é fechar a sessão onde você efetua as suas transações, pois se você precisar atualizar, inserir, deletar seu registro precisará abrir e fechar a sessão 3 vezes que é um recurso caro prejudicando a performance e escalabilidade do seu sistema. Mas usando injeção de dependência você abre a sessão e fecha somente uma vez depois que utilizar todas suas transações.

pmlm

Pensa no exemplo académico da transferência de dinheiro de uma conta para a outra. Como é que com o teu modelo garantias que atualizavas as duas contas em caso de sucesso e nenhuma em caso de erro?

T

Eu entendi bem o conceito, agora a minha outra duvida e se fazer isso manualmente em uma aplicação web é considerada uma má pratica como por exemplo esse codigo que eu fiz…

/*Criando a sessao manualmente*/ Session s = HibernateUtil.openSession(); /*Faz a injeção do session*/ HibernateDAO<TelaBean> ht = new HibernateDAO<TelaBean>(TelaBean.class,s); TelaBean t = ht.getBean(1); /*Adiciona um item na lista de permissoes*/ TelaPermissoesBean tp = new TelaPermissoesBean(); tp.setTlp_descricao("Permissão para salvar o usuario na tela de cadastro de usuarios"); tp.setTlp_nome("SALVAR"); t.addTelaPermissoes(tp); /*Salva*/ try { ht.saveOrUpdate(t); } catch (Exception ex) { Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex); } /*Fecha a sessão*/ s.close();
(Nesse exemplo, eu busco a insiro na lista)
Caso seja uma má pratica utiliza-lo manualmente, como eu devo proceder?

Muito obrigado a todos pela ajuda! :smiley:

rafadelnero

Outro detalhe, não é necessário usar commit para efetuar consultas, pode retirá-lo.
O comando commit apenas confirma transações de inserção, deleção e alteração.

sergiotaborda

tioola:
Eu entendi bem o conceito, agora a minha outra duvida e se fazer isso manualmente em uma aplicação web é considerada uma má pratica como por exemplo esse codigo que eu fiz…

claro que sim, e não apenas na web.

Vc precisa de entender que o controle da session está associado ao escopo de transação. A session começa e acada quando a transação. A transação deve começar na fronteira do serviço que a camada web invoca (nada dessas coisas de Open Session in View)

Portanto, vc precisa criar um proxy do ser serviço ( via spring AOP ou via a classe Proxy, ou uma combinação de ambos). Este proxy é quem faz aquele código. Mas ele não cria o DAO. O DAo quem cria é o spring.
O que o proxy faz é iniciar a sessão. O HibernateUtils já garante - eu acho - que se vc chamar de novo o método em outro lugar mas na mesmas thread ele lhe dá o mesmo objeto.
Então o DAO dev chamar o HibernateUtils quando precisar da sessão e pronto. O Dao não abre nem fecha a sessão ele só a utiliza. Quem abre e fecha é o proxy de serviço.

Vc aplica o proxy a todos os serviços publicos que tiver (service Façade) que precisam de transação e/ou usam chamadas ao banco.

(P.S. Não vou bater na mesma tecla que fazer um DAO com Hibernate é uma asneira, já tem uma infindável quantidade de threads sobre isso)

T

Ou seja , a cada POST eu vou ter uma session e dentro dessa session varias transações?Estou correto?

Portanto, vc precisa criar um proxy do ser serviço ( via spring AOP ou via a classe Proxy, ou uma combinação de ambos). Este proxy é quem faz aquele código. Mas ele não cria o DAO. O DAo quem cria é o spring.
O que o proxy faz é iniciar a sessão. O HibernateUtils já garante - eu acho - que se vc chamar de novo o método em outro lugar mas na mesmas thread ele lhe dá o mesmo objeto.
Então o DAO dev chamar o HibernateUtils quando precisar da sessão e pronto. O Dao não abre nem fecha a sessão ele só a utiliza. Quem abre e fecha é o proxy de serviço.

Estou estudando JSP e SERVLETS e utilizando Hibernate para persistencia (Não sera nenhum aplicativo que colocarei em produção, somente para fins didaticos). Você poderia me indicar alguma material mostrando a utilização da classe Proxy (Lembrando que não estou utilizando nenhum framework) ou exemplos?.
Então eu nao posso mais abrir e fechar sessoes dentro de um DAO farei isso com a classe proxy , Estou certo?

Vc aplica o proxy a todos os serviços publicos que tiver (service Façade) que precisam de transação e/ou usam chamadas ao banco.

Aonde eu posso achar um exemplo?

Quais tópicos com essa discussão eu posso encontrar aqui no guj?

Muito Obrigado !

sergiotaborda

Ou seja , a cada POST eu vou ter uma session e dentro dessa session varias transações?Estou correto?

1 Post, 1 Session , 1 transação

Vc está usando hibernate que é um framework , :lol: :lol:
Na real, vc precisa usar pelo menos o spring, ou vai ser impossivel explicar para vc como fazer na mão.
Procure por spring, use ele, e depois que vc souber injetar os serviços nos actions/servlets procure por BeanPosProcessor

Sim.

Aonde eu posso achar um exemplo?

O Proxy é uma classe padrão do java. Procure no gogle por “Proxy javadoc”

Tem este aqui que resume a opera, mais ou menos.

T

Ou seja , a cada POST eu vou ter uma session e dentro dessa session varias transações?Estou correto?

1 Post, 1 Session , 1 transação

Vc está usando hibernate que é um framework , :lol: :lol:
Na real, vc precisa usar pelo menos o spring, ou vai ser impossivel explicar para vc como fazer na mão.
Procure por spring, use ele, e depois que vc souber injetar os serviços nos actions/servlets procure por BeanPosProcessor

Sim.

Aonde eu posso achar um exemplo?

O Proxy é uma classe padrão do java. Procure no gogle por “Proxy javadoc”

Tem este aqui que resume a opera, mais ou menos.

Caramba!, eu comecei aqui com uma pergunta e ja achei mais um monte de coisa pra ver e estudar, esse assunto é bem complicado(Pelo menos pra mim que ainda estou começando).
De qualquer forma voces me ajudaram muito.
Obrigado!

Criado 26 de fevereiro de 2013
Ultima resposta 26 de fev. de 2013
Respostas 10
Participantes 4