DAO Generico quando fechar sessões

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

[code]public class HibernateDAO {
private Class 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();
    }
}

}[/code]

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!

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.

[quote=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.

[/quote]

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

[quote=tioola][quote=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.

[/quote]

Então o correto não seria fechar a session dentro do HibernateDAO?[/quote]

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.

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?

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:

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.

[quote=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…
[/quote]

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)

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

[quote]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.[/quote]

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?

[quote]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.
[/quote]

Aonde eu posso achar um exemplo?

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

Muito Obrigado !

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

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?

[/quote]

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

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

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

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?

[/quote]

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

Tem este aqui que resume a opera, mais ou menos.[/quote]

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!