Meu Generic DAO - Opinião e Crítica

35 respostas
A

Boa tarde pessoal.

Sou novo no mundo Java e muito entusiasmado. Vim do mundo desktop e PHP. Estou criando um programinha para aprendizado de JSF 2 + Hibernate 3. Meu ponto fraco é OO e padrões de projeto. Criei um Generic DAO e gostaria da opinião de vocês. Este negócio de Hibernate com JPA me confunde…rsss
Alguma opinião, crítica, etc?

GenericDAO:

package br.com.futurize.persistencia;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import br.com.futurize.seguranca.PermissaoClasses;
import br.com.futurize.seguranca.PermissaoException;
import br.com.futurize.util.ConfigCadastro;
import br.com.futurize.util.ConstantesGerais;

@SuppressWarnings("unchecked")
public class GenericDAO<T> {

	@SuppressWarnings("rawtypes")
	private Class persistentClass;
	private Session session;

	private String prefixo   = "";
	private String tabela    = "";
	private String fieldId   = "";
	private String fieldNome = "";
	
	@SuppressWarnings("rawtypes")
	protected GenericDAO(Session p_session, Class p_persistentClass) {
		if ((p_session == null) || (!session.isOpen()))
			session = HibernateUtil.getSession();
		else		
			session = p_session;
		
		persistentClass = p_persistentClass;
	}
	
	public Session getSession() {
		return session;
	}

	@SuppressWarnings("rawtypes")
	public Class getPersistentClassLocal(){
		return persistentClass;
	}
	
	public void insert(T obj) throws Exception {		
		Transaction transaction = session.beginTransaction();		
		try {
			
			if (!PermissaoClasses.VerificaPermissao(ConstantesGerais.PERMISAO_INSERT, persistentClass))
				throw new PermissaoException("Permissão Negada para Inserção - " + PermissaoClasses.getDescricaoClasse(persistentClass.getName()));
			
			session.save(obj);
			session.flush();
			transaction.commit();
			
		} catch (Exception e) {
			transaction.rollback();
			throw new Exception(e);
		}	
	}

	public void update(T obj) throws Exception {
		Transaction transaction = session.beginTransaction();
		
		try {
			
			if (!PermissaoClasses.VerificaPermissao(ConstantesGerais.PERMISAO_UPDATE, persistentClass))
				throw new PermissaoException("Permissão Negada para Atualização - " + PermissaoClasses.getDescricaoClasse(persistentClass.getName()));
						
			session.update(obj);
			session.flush();
			transaction.commit();
			
		} catch (Exception e) {
			transaction.rollback();
			throw new Exception(e);
		}	
	}
		
	public void delete(T obj) throws Exception {
		Transaction transaction = session.beginTransaction();
		
		try {
			
			if (!PermissaoClasses.VerificaPermissao(ConstantesGerais.PERMISAO_DELETE, persistentClass))
				throw new PermissaoException("Permissão Negada para Exclusão - " + PermissaoClasses.getDescricaoClasse(persistentClass.getName()));
			
			session.delete(obj);
			session.flush();
			transaction.commit();
			
		} catch (Exception e) {
			transaction.rollback();
			throw new Exception(e);
		}	
	}

	public Integer count(List<Criterion> criterion) throws Exception {
		try {
			
			Criteria criteria = session.createCriteria(persistentClass);
			
			for (Criterion c: criterion)
				criteria.add(c);
			
			criteria.setProjection(Projections.rowCount());
			return ((Integer) criteria.uniqueResult()).intValue();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public List<T> listAll(String fieldOrder, String ord) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			addOrder(criteria, fieldOrder, ord);
			return criteria.list();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}
	
	public List<T> listAll(int first, int max, String fieldOrder, String ord, List<Criterion> criterion) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			addOrder(criteria, fieldOrder, ord);

			for (Criterion c: criterion)
				criteria.add(c);
			
			if (first != 0)
				criteria.setFirstResult(first - 1);

			if (max != 0)
				criteria.setMaxResults(max);

			return criteria.list();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}
	
	public List<T> listAllCadastro(int first, int max, String fieldOrder, String ord, List<Criterion> criterion) throws Exception {
		try {
			
			if (!PermissaoClasses.VerificaPermissao(ConstantesGerais.PERMISAO_CADASTRO, persistentClass))
				throw new PermissaoException("Permissão Negada para Seleção - " + PermissaoClasses.getDescricaoClasse(persistentClass.getName()));
			
			return listAll(first, max, fieldOrder, ord, criterion);
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public T findById(Long id) throws Exception {
		try {
			
			return (T) session.get(persistentClass, id);
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public String findByNome(Long id) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(getFieldId(), id)).setProjection(Projections.property(getFieldNome()));
			criteria.uniqueResult();
			if (criteria.uniqueResult() == null)
				return "";
			else
				return criteria.uniqueResult().toString();
		
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public String findByColumn(Long id, String column) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(getFieldId(), id)).setProjection(Projections.property(column));
			criteria.uniqueResult();
			if (criteria.uniqueResult() == null)
				return "";
			else
				return criteria.uniqueResult().toString();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public String findByColumnValue(String findColumn, String findValue, String fieldReturn) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(findColumn, findValue)).setProjection(Projections.property(fieldReturn));
			if (criteria.uniqueResult() == null)
				return "";
			else
				return criteria.uniqueResult().toString();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public String findByColumnValue(String findColumn, Long findValue, String fieldReturn) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(findColumn, findValue)).setProjection(Projections.property(fieldReturn));
			if (criteria.uniqueResult() == null)
				return "";
			else
				return criteria.uniqueResult().toString();
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public Boolean isUsedCadastro(String findColumnFK, Long findValue) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(findColumnFK, findValue));
			Integer totalResult = (Integer)criteria.setProjection(Projections.rowCount()).uniqueResult();
  			return totalResult > 0;
  		
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public Boolean isUsedCadastro(String findColumnFK, String findValue) throws Exception {
		try {

			Criteria criteria = session.createCriteria(persistentClass);
			criteria.add(Restrictions.eq(findColumnFK, findValue));
			Integer totalResult = (Integer)criteria.setProjection(Projections.rowCount()).uniqueResult();
			return totalResult > 0;
			
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public List<T> findByCriteria(List<Criterion> criterion) throws Exception {
		try {
		
			Criteria criteria = session.createCriteria(persistentClass);

			if (criterion == null)
				return null;

			for (Criterion c: criterion)
				criteria.add(c);

			return criteria.list();
	    
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public List<Object[]> query(String sql) throws Exception {
		try {
			
			Query select = session.createQuery(sql);
			return select.list();

		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	public int sqlUpdate(String sql) throws Exception {
		try {
			
			int rowCount = 0;
			Query query = session.createQuery(sql);
			rowCount = query.executeUpdate();
			return rowCount;
		
		} catch (Exception e) {
			throw new Exception(e);
		}	
	}

	private Criteria addOrder(Criteria criteria, String fieldOrder, String ord) {

		if (!fieldOrder.isEmpty()) {
			if ((ord.toUpperCase().equals("ASC")) || (ord.isEmpty()))
				criteria.addOrder(Order.asc(fieldOrder));

			if (ord.toUpperCase().equals("DESC"))
				criteria.addOrder(Order.desc(fieldOrder));
		}
		return criteria;
	}
		
	//gets e sets

}

ClientesDAO:

package br.com.futurize.persistencia;

import org.hibernate.Session;

import br.com.futurize.dominio.Clientes;

@SuppressWarnings({"rawtypes", "unused"})
public class ClientesDAO extends GenericDAO<Clientes> {

	private Session sessionLocal;
	private Class persistentClassLocal = Clientes.class;

	public ClientesDAO(Session session) {
		super(session, Clientes.class);
		super.setPrefixo("clf");
		super.setPrefixo("clientes");
		super.setFieldId("clf_CLIENTE");
		super.setFieldNome("clf_nome");
		this.sessionLocal = session;
		this.persistentClassLocal = super.getPersistentClassLocal();
	}

}

Muito obrigado a todos e fiquem com Deus
Ademir - BH

35 Respostas

A

Ninguém… :frowning:

É que eu preciso saber se está ok para dar continuidade ao projeto.

Msm assim obrigado pelas 50 visualizações…rsss

Abraços a todos
Ademir

J

E ae cara?

Então, eu particularmente achei seu DAO muito grande. Não precisa ter tantas funcionalidades assim não. Em OO se a classe tá ficando muito grande, tá na hora de refatorar.

E outra coisa, você usa um try catch apenas para throws? Você pode tirar o try catch e deixar só o throws no método que funciona. :smiley:

D

AdemirPinto:
Ninguém… :frowning:

É que eu preciso saber se está ok para dar continuidade ao projeto.

Msm assim obrigado pelas 50 visualizações…rsss

Abraços a todos
Ademir

Amigo eu achei suas classes interessante… inclusive vc esta usando bastante padrão… e achei legal que aprendeu rápido para quem veio do PHP, quanto tempo vc estudou Java? tem algum documento legal para indicar?

Agora uma dúvida que eu fiquei aqui porque vc cria suas classes genericas e etc… como funciona isso é do proprio Java?

A

Confesso que a primeira vez que eu olhei, desisti quando vi o tamanho do código…

Achei interessante que você facilitou muito para as implementações reais de DAO…

Uma melhoria que faria é a seguinte:

A transação é importante para executar vários comandos em um bloco só: roda tudo ou nada…

Se no método do DAO você dá begin e commit, perde esse efeito…pois terá um commit a cada comando!

Uma solução seria passar a transação para o construtor do DAO, e outra classe gerenciar begins, commits e rollbacks…

R

Dá uma olhada no meu DAO:

public class GenericDAOImp&lt;T,ID extends Serializable&gt; implements GenericDAO&lt;T, ID&gt; {
	@PersistenceContext(type=PersistenceContextType.EXTENDED)
	private EntityManager entityManager;
	private final Class&lt;T&gt; classePersistente;

	public GenericDAOImp(){
		this.classePersistente = (Class&lt;T&gt;)
		((ParameterizedType)getClass().getGenericSuperclass())
		.getActualTypeArguments()[0];
	}

	public Class&lt;T&gt; getClassePersistente() {return classePersistente;}
	
	protected final Criteria criaCriteria() {
		return criaSession().createCriteria(getClassePersistente());
	}

	public final Session criaSession() {
		return  (Session)getEntityManager().getDelegate();
	}
	public EntityManager getEntityManager() {return entityManager;}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	public Class&lt;T&gt; getObjectClass() {return this.classePersistente;}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T salvar(T object)  {
		getEntityManager().clear();
		try {
			getEntityManager().persist(object);
		}catch(Exception e){
			e.printStackTrace();
		}
		return object;
	}

	@SuppressWarnings("unchecked")       
	public List&lt;T&gt; todos(String ordem){ 
		StringBuffer queryS = new StringBuffer("SELECT obj FROM "+classePersistente.getSimpleName()+" obj "); 
		if(ordem!=null){
			queryS.append("order by "+ordem);
		}
		Query query = getEntityManager().createQuery(queryS.toString()); 
		return query.getResultList(); 
	}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T atualizar(T object) {
		getEntityManager().merge(object);
		return null;
	}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T excluir(T object) {
		try {
			object = getEntityManager().merge(object);
			getEntityManager().remove(object);
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T findById(ID id) {
		return getEntityManager().find(getClassePersistente(), id);
	}

	@Override
	public void refresh(Object object) {
		getEntityManager().refresh(object);
	}
A

javablue:
E ae cara?

Então, eu particularmente achei seu DAO muito grande. Não precisa ter tantas funcionalidades assim não. Em OO se a classe tá ficando muito grande, tá na hora de refatorar.

E outra coisa, você usa um try catch apenas para throws? Você pode tirar o try catch e deixar só o throws no método que funciona. :smiley:

Valeu pelas dicas Javablue,

vou tirar os try e catch. Me fala uma coisa qual a sua sugestão de refatorar minha classe?

Muito obrigado a todos pelas respostas. Vou responder a todos.
Ademir

A

AbelBueno:
Confesso que a primeira vez que eu olhei, desisti quando vi o tamanho do código…

Achei interessante que você facilitou muito para as implementações reais de DAO…

Uma melhoria que faria é a seguinte:

A transação é importante para executar vários comandos em um bloco só: roda tudo ou nada…

Se no método do DAO você dá begin e commit, perde esse efeito…pois terá um commit a cada comando!

Uma solução seria passar a transação para o construtor do DAO, e outra classe gerenciar begins, commits e rollbacks…

Olá AbelBueno,

obrigado pelo retorno. Vou melhorar esta classe com relação à transção conforme sua ideia. Vc tem uma ideia de como seria uma outra classe pra fazer este controle de transação?

Muito obrigado!
Ademir

A
raf4ever:
Dá uma olhada no meu DAO:
public class GenericDAOImp&lt;T,ID extends Serializable&gt; implements GenericDAO&lt;T, ID&gt; {
	@PersistenceContext(type=PersistenceContextType.EXTENDED)
	private EntityManager entityManager;
	private final Class&lt;T&gt; classePersistente;

	public GenericDAOImp(){
		this.classePersistente = (Class&lt;T&gt;)
		((ParameterizedType)getClass().getGenericSuperclass())
		.getActualTypeArguments()[0];
	}

	public Class&lt;T&gt; getClassePersistente() {return classePersistente;}
	
	protected final Criteria criaCriteria() {
		return criaSession().createCriteria(getClassePersistente());
	}

	public final Session criaSession() {
		return  (Session)getEntityManager().getDelegate();
	}
	public EntityManager getEntityManager() {return entityManager;}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	public Class&lt;T&gt; getObjectClass() {return this.classePersistente;}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T salvar(T object)  {
		getEntityManager().clear();
		try {
			getEntityManager().persist(object);
		}catch(Exception e){
			e.printStackTrace();
		}
		return object;
	}

	@SuppressWarnings("unchecked")       
	public List&lt;T&gt; todos(String ordem){ 
		StringBuffer queryS = new StringBuffer("SELECT obj FROM "+classePersistente.getSimpleName()+" obj "); 
		if(ordem!=null){
			queryS.append("order by "+ordem);
		}
		Query query = getEntityManager().createQuery(queryS.toString()); 
		return query.getResultList(); 
	}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T atualizar(T object) {
		getEntityManager().merge(object);
		return null;
	}

	@Override 
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T excluir(T object) {
		try {
			object = getEntityManager().merge(object);
			getEntityManager().remove(object);
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
	public T findById(ID id) {
		return getEntityManager().find(getClassePersistente(), id);
	}

	@Override
	public void refresh(Object object) {
		getEntityManager().refresh(object);
	}

raf4ever,

como que funciona este EntityManager? Isso é spring? Desculpe a ignorância.

Obrigado pela resposta.
Ademir

A

dtxk:
AdemirPinto:
Ninguém… :frowning:

É que eu preciso saber se está ok para dar continuidade ao projeto.

Msm assim obrigado pelas 50 visualizações…rsss

Abraços a todos
Ademir

Amigo eu achei suas classes interessante… inclusive vc esta usando bastante padrão… e achei legal que aprendeu rápido para quem veio do PHP, quanto tempo vc estudou Java? tem algum documento legal para indicar?

Agora uma dúvida que eu fiquei aqui porque vc cria suas classes genericas e etc… como funciona isso é do proprio Java?

Fala dtxk,

obrigado pelos elogios…rsss Estou só começando, na verdade eu juntei uns Generic DAO daqui do forum, juntei conforme minha necessidade e aquilo que eu ia compreendendo, não queria uma coisa muito sofisticada e complexa. Sobre como aprendi, além de ser formado em Ciencia da Computação pela Universidade Federal de Viçosa-MG, pra mim a net é a sala de aula e o google é meu livro…rssss
Eu usei gerericas para exatamente ter como extender nas classes especificas: como ClienteDAO, FornecedorDAO, ContaBancariaDAO, etc…acho que é por este motivo…ou estou falando bobagem???rsss

Abraços
Ademir

V

Eu sou contra herdar um dao genérico em cada um de seus daos. O dao genérico possui inúmeros comportamentos que geralmente o dao filho nunca vai usar, gerando herança desnecessária. Ao invés disso, injete o dao genérico pelo construtor, e faça uso dele quando for necessário.

Tenho que enfrentar problemas enormes de herança graças a daos genéricos desnecessários. :?

A

von.juliano:
Eu sou contra herdar um dao genérico em cada um de seus daos. O dao genérico possui inúmeros comportamentos que geralmente o dao filho nunca vai usar, gerando herança desnecessária. Ao invés disso, injete o dao genérico pelo construtor, e faça uso dele quando for necessário.

Tenho que enfrentar problemas enormes de herança graças a daos genéricos desnecessários. :?

Obrigado von.juliano pelas suas criticas que são de muito valia. Vc tem aí um exemplo de injeção de dao generico?

Abraços
Ademir

M

eu achei legal por que deu para ver que você caprichou… pensou em fazer tomando cuidado com os detalhes…até por quÊ ficou grande… confesso que também não li tudo com calma, só dei uma olhadinha.

Algumas dicas que a experiência e alguns estudos demonstram para agente:

Evite deixar o dao gerenciar sua session do hibernate… assim fica mais dificil de você sempre fecha-la da forma correta… sempre passe a sessão para o seu Dao e caso ela esteja fechada lance uma exceção por exemplo… dao não deveria abrir sessão, o seu modelo, seila, seu BO deve abrir a sessão, passar uma sessão válida para os daos fazerem o que tiverem que fazer e ai no BO você comita ou da rollback caso tenha dado erro, assim vai comitar ou rollbackear tudo o que foi feito (a menos que a regra de negócio seja comitar só uma metade caso só ela tenha dado certo e dar rollback no que não deu, o que eu nunca vi, e mesmo que seja essa a ideia, dao não é lugar de regra de negócio, é lugar de operação com o banco pura e simples). Não se esqueça de ter um try catch no seu BO dando commit no final do try, rollback no catch.

quanto aos try catchs do dao, eles serão necessários caso você queira fazer alguma coisa em caso de erro (obvio, é a utilidade mais básica do try catch…). Como acabei de indicar você a deixar o rollback em outro lugar ele a principio não teria mais utilidade, mas eu te indico que em caso de erro você gere um log no dao dizendo o que vocÊ estava tentando inserir/atualizar/busca/deletar… logando por exemplo a classe e método do seu dao e o toString do pojo que você estava tentando… fazer o que estava fazendo, assim é facil detectar o que aconteceu no futuro em caso de algum erro. Ja que seria esse log só no caso de erro, ele deve ficar no catch, tornando-o necessário, não se esqueça de dar o throw depois disso para avisar a camada de cima (um BO por exemplo) que o erro aconteceu, assim ela pode tomar a decisão que precisar, dar o rollback na sessão do hibernate, avisar o controller para que este então redirecione para uma tela de erro por exemplo. Eu gosto de além de logar no dao quais eram as informações que deu erro ao inserir por exemplo, logar no modelo alguma coisa do tipo “erro ao …”.

Procure deixar seus pojos sempre com o fech Lazy, para ficar mais leve ao obter suas entidades no banco. é possivel que vocÊ tenha problemas de Lazy Innicialization, a dica abaixo resolve.

Para gerenciar como você abre sua sessão do hibernate (e como fecha), eu te aconselharia ver o padrão Open Session In View…

essa é uma leitura muito boa, mas isso é só mais para frente…

bom… no demais parabéns… gostei muito do seu dao e se me permite peço para pegar ele e adapta-lo…

V
Ao invés de extender o dao genérico:
class ClientesDAO extends GenericDAO<Clientes>
você o passa pelo construtor:
class ClientesDAO {

	ClientesDAO(GenericDAO dao) {...}
}
Aí você cria os métodos que o ClienteDao deve ter, que provavelmente serão uma quantidade muito menor do que os que existem no dao genérico, e o utiliza quando necessário.

Uma dica para quem está começando: herança é um perigo, muito cuidado!

A
von.juliano:
Ao invés de extender o dao genérico:
class ClientesDAO extends GenericDAO<Clientes>
você o passa pelo construtor:
class ClientesDAO {

	ClientesDAO(GenericDAO dao) {...}
}
Aí você cria os métodos que o ClienteDao deve ter, que provavelmente serão uma quantidade muito menor do que os que existem no dao genérico, e o utiliza quando necessário.

Uma dica para quem está começando: herança é um perigo, muito cuidado!

Fala von.juliano. Cara agora vc me deixou confuso...rsss Uma das ideias de herança não é remover código duplicado e coloca-lo na classe pai? Como assim que herança é perigoso?
Como que funciona este negocio de injeção do dao generico?

Abraços e muito obrigado
Ademir

A

maior_abandonado:
eu achei legal por que deu para ver que você caprichou… pensou em fazer tomando cuidado com os detalhes…até por quÊ ficou grande… confesso que também não li tudo com calma, só dei uma olhadinha.

Algumas dicas que a experiência e alguns estudos demonstram para agente:

Evite deixar o dao gerenciar sua session do hibernate… assim fica mais dificil de você sempre fecha-la da forma correta… sempre passe a sessão para o seu Dao e caso ela esteja fechada lance uma exceção por exemplo… dao não deveria abrir sessão, o seu modelo, seila, seu BO deve abrir a sessão, passar uma sessão válida para os daos fazerem o que tiverem que fazer e ai no BO você comita ou da rollback caso tenha dado erro, assim vai comitar ou rollbackear tudo o que foi feito (a menos que a regra de negócio seja comitar só uma metade caso só ela tenha dado certo e dar rollback no que não deu, o que eu nunca vi, e mesmo que seja essa a ideia, dao não é lugar de regra de negócio, é lugar de operação com o banco pura e simples). Não se esqueça de ter um try catch no seu BO dando commit no final do try, rollback no catch.

quanto aos try catchs do dao, eles serão necessários caso você queira fazer alguma coisa em caso de erro (obvio, é a utilidade mais básica do try catch…). Como acabei de indicar você a deixar o rollback em outro lugar ele a principio não teria mais utilidade, mas eu te indico que em caso de erro você gere um log no dao dizendo o que vocÊ estava tentando inserir/atualizar/busca/deletar… logando por exemplo a classe e método do seu dao e o toString do pojo que você estava tentando… fazer o que estava fazendo, assim é facil detectar o que aconteceu no futuro em caso de algum erro. Ja que seria esse log só no caso de erro, ele deve ficar no catch, tornando-o necessário, não se esqueça de dar o throw depois disso para avisar a camada de cima (um BO por exemplo) que o erro aconteceu, assim ela pode tomar a decisão que precisar, dar o rollback na sessão do hibernate, avisar o controller para que este então redirecione para uma tela de erro por exemplo. Eu gosto de além de logar no dao quais eram as informações que deu erro ao inserir por exemplo, logar no modelo alguma coisa do tipo “erro ao …”.

Procure deixar seus pojos sempre com o fech Lazy, para ficar mais leve ao obter suas entidades no banco. é possivel que vocÊ tenha problemas de Lazy Innicialization, a dica abaixo resolve.

Para gerenciar como você abre sua sessão do hibernate (e como fecha), eu te aconselharia ver o padrão Open Session In View…

essa é uma leitura muito boa, mas isso é só mais para frente…

bom… no demais parabéns… gostei muito do seu dao e se me permite peço para pegar ele e adapta-lo…

Fala maior_abandonado…muito boas as suas explanações. Achei muito interessante sobre o Open Session In View.
Alguém aqui da lista está usando ele a risca ou fez alguma adaptação. O que eu acho mais complicado em usar o filter pra controlar transação seria o controle de qual erro aconteceu e um tratamento para mostrar para o usuário. Mas a ideia é muito interessante e estou querendo usa-la.

Abraços
Ademir

M

Fala maior_abandonado…muito boas as suas explanações. Achei muito interessante sobre o Open Session In View.
Alguém aqui da lista está usando ele a risca ou fez alguma adaptação. O que eu acho mais complicado em usar o filter pra controlar transação seria o controle de qual erro aconteceu e um tratamento para mostrar para o usuário. Mas a ideia é muito interessante e estou querendo usa-la.

então… na prática eu até deveria ter alguma coisa anotada, para alterar conforme necessidade, mas um padrão de start para algumas coisas que são repetitivas, muitas aplicações tem mas eu não tenho… apesar disso acho que qualquer implementação que siga essa idéia é válida… o importante é você colocar alguma coisa para abrir a sessão do hibernate antes de você precisar dela, ela ficar disponivel onde você precisar (você pode deixa-la na sessão ou usar um objeto de uma classe chamada ThreadLocal em uma classe segundaria como um HibernateUtils por exemplo) e depois de ter feito o que precisa fechar a conexão… você pode usar filters para isso (e se você diz que está começando é o que eu te indico agora), mas normalmente usa-se algum framework MVC, se você estiver usando, geralmente os frameworks de MVC (ao menos os não muito antigos) que você possa usar tem alguma funcionalidade semelhante que possa te ajudar nisso, os PhaseListeners do JSF, os Interruptors do struts, indo um pouco mais além poderia ser injetada a sessão na sua classe, ai entraria num spring ou num EJB por exemplo (assunto para você estudar mais para frente, bem legal). Resumidamente existem várias formas de seguir este padrão, depende do framework que você está usando, da arquitetura da aplicação…

editando…

esse exemplo ai que você colocou foi o primeiro resultado no google né… eu tinha procurado algum link que eu achasse legal mas não achei… (ai falei para você procurar :D), esse exemplo coloca para dar o commit e o rollback no filter… eu não gosto muito dessa abordagem por que não me parece viavel o filter saber se deu algum erro ou não (isso é assunto de algum componente dentro do controller e/ou do modelo, esse filter ai é só para disponibilizar e fechar a sessão), se ele não deve saber, não é ele que deve dar o commit ou o rollback, ou seja, para mim ele não deveria gerenciar essa parte transacional…

o filter ainda deve lançar uma exceção em caso de não conseguir abrir a sessão (e assim o usuário deveria ser redirecionado para uma tela de erro)… mas se ele conseguiu abrir, deu o chain e chamou a aplicação e deu erro na hora de fechar, ai a minha opinião é que vocÊ não deveria alterar qual a página que o usuário vai, apenas logar o problema. Isso pode ser caracteristico de bug, sei la, você fechou a sessão no meio da aplicação e ao tentar fechar no filter ja estava fechada, ou perdeu a conexão com o banco no meio do processamento… mas se o usuário iria para uma página normal na aplicação acho que ele deveria continuar indo, se ele iria para a página que você iria exibir um erro especifico e você impedir que vá para lá para mostrar outro erro de que você não conseguiu fechar a conexão, você pode estar mascarando um outro problema…

V

O porque é um assunto que já foi muito discutido, e há muito material sobre, então vou te passar alguns artigos e um link do guj, que explicam o porque de usar composição ao invés de herança:

http://www.guj.com.br/java/2542-composicao-versus-heranca
http://www.artima.com/designtechniques/compoinh.html


http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/herancavscomposicao.htm

Blz? Flw! :thumbup:

A

maior_abandonado:
Fala maior_abandonado…muito boas as suas explanações. Achei muito interessante sobre o Open Session In View.
Alguém aqui da lista está usando ele a risca ou fez alguma adaptação. O que eu acho mais complicado em usar o filter pra controlar transação seria o controle de qual erro aconteceu e um tratamento para mostrar para o usuário. Mas a ideia é muito interessante e estou querendo usa-la.

então… na prática eu até deveria ter alguma coisa anotada, para alterar conforme necessidade, mas um padrão de start para algumas coisas que são repetitivas, muitas aplicações tem mas eu não tenho… apesar disso acho que qualquer implementação que siga essa idéia é válida… o importante é você colocar alguma coisa para abrir a sessão do hibernate antes de você precisar dela, ela ficar disponivel onde você precisar (você pode deixa-la na sessão ou usar um objeto de uma classe chamada ThreadLocal em uma classe segundaria como um HibernateUtils por exemplo) e depois de ter feito o que precisa fechar a conexão… você pode usar filters para isso (e se você diz que está começando é o que eu te indico agora), mas normalmente usa-se algum framework MVC, se você estiver usando, geralmente os frameworks de MVC (ao menos os não muito antigos) que você possa usar tem alguma funcionalidade semelhante que possa te ajudar nisso, os PhaseListeners do JSF, os Interruptors do struts, indo um pouco mais além poderia ser injetada a sessão na sua classe, ai entraria num spring ou num EJB por exemplo (assunto para você estudar mais para frente, bem legal). Resumidamente existem várias formas de seguir este padrão, depende do framework que você está usando, da arquitetura da aplicação…

Então maior_abandonado, com relação à session eu vou usar algum start msm, eu uso o PhaseListeners para segurança, poderia usar ele pra iniciar e fechar a sessão? Agora e a transação como eu poderia fazer? Neste meu projeto eu estou usando JSF 2, JPA 2 e Hibernate 3. Não estou querendo pindurar muitos frameworks para nao ficar confuso. Mas qualquer sugestão é bem vinda.

Abraços e mais uma vez muito obrigado.
Ademir

A

von.juliano:
O porque é um assunto que já foi muito discutido, e há muito material sobre, então vou te passar alguns artigos e um link do guj, que explicam o porque de usar composição ao invés de herança:

http://www.guj.com.br/java/2542-composicao-versus-heranca
http://www.artima.com/designtechniques/compoinh.html


http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/herancavscomposicao.htm

Blz? Flw! :thumbup:

Obrigado von.juliano, vou ler todos, nao pesquisei sobre este assunto é porque nem sabia dessa historia de composição vs herança…rsss

Abraços
Ademir

M

AdemirPinto:

Então maior_abandonado, com relação à session eu vou usar algum start msm, eu uso o PhaseListeners para segurança, poderia usar ele pra iniciar e fechar a sessão? Agora e a transação como eu poderia fazer? Neste meu projeto eu estou usando JSF 2, JPA 2 e Hibernate 3. Não estou querendo pindurar muitos frameworks para nao ficar confuso. Mas qualquer sugestão é bem vinda.

Abraços e mais uma vez muito obrigado.
Ademir

você pode usar mais de um PhaseListener, um para gerenciar a sessão do hibernate e outro para segurança, para ver se o usuário está logado por exemplo… nada impede… você pode também continuar gerenciando a sessão do hibernate em um Filter (nada impede).

quanto a abrir a transação, commitar ou dar rollback, eu indico você a chamar isso na sua classe de negócio la no modelo mesmo, na sua classe de negócio você pega a sessão ativa, faz tudo o que tem que fazer, se der alguma exceção (seja de negócio, de banco de dados), você pode dar algum rollback no catch dali, lançando ainda a exceção para o controller para ele saber disso e informar o usuário.

D

maior_abandonado:
eu achei legal por que deu para ver que você caprichou… pensou em fazer tomando cuidado com os detalhes…até por quÊ ficou grande… confesso que também não li tudo com calma, só dei uma olhadinha.

Algumas dicas que a experiência e alguns estudos demonstram para agente:

Evite deixar o dao gerenciar sua session do hibernate… assim fica mais dificil de você sempre fecha-la da forma correta… sempre passe a sessão para o seu Dao e caso ela esteja fechada lance uma exceção por exemplo… dao não deveria abrir sessão, o seu modelo, seila, seu BO deve abrir a sessão, passar uma sessão válida para os daos fazerem o que tiverem que fazer e ai no BO você comita ou da rollback caso tenha dado erro, assim vai comitar ou rollbackear tudo o que foi feito (a menos que a regra de negócio seja comitar só uma metade caso só ela tenha dado certo e dar rollback no que não deu, o que eu nunca vi, e mesmo que seja essa a ideia, dao não é lugar de regra de negócio, é lugar de operação com o banco pura e simples). Não se esqueça de ter um try catch no seu BO dando commit no final do try, rollback no catch.

quanto aos try catchs do dao, eles serão necessários caso você queira fazer alguma coisa em caso de erro (obvio, é a utilidade mais básica do try catch…). Como acabei de indicar você a deixar o rollback em outro lugar ele a principio não teria mais utilidade, mas eu te indico que em caso de erro você gere um log no dao dizendo o que vocÊ estava tentando inserir/atualizar/busca/deletar… logando por exemplo a classe e método do seu dao e o toString do pojo que você estava tentando… fazer o que estava fazendo, assim é facil detectar o que aconteceu no futuro em caso de algum erro. Ja que seria esse log só no caso de erro, ele deve ficar no catch, tornando-o necessário, não se esqueça de dar o throw depois disso para avisar a camada de cima (um BO por exemplo) que o erro aconteceu, assim ela pode tomar a decisão que precisar, dar o rollback na sessão do hibernate, avisar o controller para que este então redirecione para uma tela de erro por exemplo. Eu gosto de além de logar no dao quais eram as informações que deu erro ao inserir por exemplo, logar no modelo alguma coisa do tipo “erro ao …”.

Procure deixar seus pojos sempre com o fech Lazy, para ficar mais leve ao obter suas entidades no banco. é possivel que vocÊ tenha problemas de Lazy Innicialization, a dica abaixo resolve.

Para gerenciar como você abre sua sessão do hibernate (e como fecha), eu te aconselharia ver o padrão Open Session In View…

essa é uma leitura muito boa, mas isso é só mais para frente…

bom… no demais parabéns… gostei muito do seu dao e se me permite peço para pegar ele e adapta-lo…

referente a como abrir oou fechar o hibernate não seria legal deixar com o HibernateTemplate do Spring?

Abraços!

M

honestamente não conheço spring…

conheço injeção de dependencia, sei que da para injetarmos a sessão mas ai nem entrei no que ele poderia fazer com o spring por quê não conheço o framework… estava me referindo ao padrão mesmo.

mas então… o que o HibernateTemplate faz?

A

Pessoal,

segui alguns conselhos do pessoal e melhorei bem meu Generic DAO(parte do código abaixo)...muito obrigado a todos.

Só que ainda falta alguns detalhes e dentre eles a questão da Sessão e Transação. Com relação à sessão eu fiz um filter para criar ele e depois em cada requisição eu a recupero, conforme o código abaixo. As dúvidas ainda são:

1)Vocês acham que ficou bom meu HibernateSessionRequestFilter?

2)Estava pensando em fazer o controle de transação nos meus Managed Bean, o que voces acham?

3)No site http://community.jboss.org/wiki/OpenSessioninView tem uma implementação com o controle de transação no filter, isso não é complicado? Tipo eu quero fazer um controle melhorar das minhas exceções para tratar a saida para o usuario. Outra coisa é que ele fica dando beginTransaction e depois commit, mas pode acontecer que a requisição não alterou o banco de dados. O que vocês acham dessa implementação? Vale a pena fazer o controle de transação assim?

HibernateSessionRequestFilter:
public class HibernateSessionRequestFilter implements Filter {
	 
    private SessionFactory sf;
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Throwable ex) {
            ex.printStackTrace();
            throw new ServletException(ex);
        }
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
    	System.out.println("Initializing filter...");
    	System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");
    	sf =  HibernateUtil.getInstace().getSessionFactory();     
    	sf.openSession(); 
    }
 
    public void destroy() {
    	
    }

}
HibernateUtil:
public class HibernateUtil {
	
	private static HibernateUtil me;
	private SessionFactory sessionFactory;

	public HibernateUtil() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}

	public Session getSession() {
		Session toReturn = sessionFactory.openSession();
		return toReturn;
	}

	public static HibernateUtil getInstace() {
		if (me == null) {
			me = new HibernateUtil();
		}
		return me;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
GenericDAO:
@SuppressWarnings("unchecked")
public class GenericDAO<T> {

	@SuppressWarnings("rawtypes")
	private Class persistentClass;
	private Session session;

	//Construtor - ##########################################
	@SuppressWarnings("rawtypes")
	protected GenericDAO(Class p_persistentClass) {
		session = HibernateUtil.getInstace().getSession();		
		persistentClass = p_persistentClass;
	}
	
	public Session getSession() {
		return session;
	}

	@SuppressWarnings("rawtypes")
	public Class getPersistentClassLocal(){
		return persistentClass;
	}
	
	public void insert(T obj) throws Exception {		
		session.save(obj);
		session.flush();
	}

	public void update(T obj) throws Exception {
		session.update(obj);
		session.flush();
	}
	
	public void delete(T obj) throws Exception {
		session.delete(obj);
		session.flush();
	}

	public Integer count(List<Criterion> criterion) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);
			
		for (Criterion c: criterion)
			criteria.add(c);
			
		criteria.setProjection(Projections.rowCount());
		return ((Integer) criteria.uniqueResult()).intValue();
	}

	//Lista todos os registros com ordem e sem limite
	public List<T> listAll(String fieldOrder, SortOrder sortOrder) throws Exception {
		String ord = ConstantesGerais.TIPOORDEMASC; 
		if (sortOrder == SortOrder.DESCENDING)  
			ord = ConstantesGerais.TIPOORDEMDESC;  
			
		Criteria criteria = session.createCriteria(persistentClass);
		addOrder(criteria, fieldOrder, ord);
		return criteria.list();
	}

...

Abraços a todos e um bom FDS.
Ademir

D

maior_abandonado:
honestamente não conheço spring…

conheço injeção de dependencia, sei que da para injetarmos a sessão mas ai nem entrei no que ele poderia fazer com o spring por quê não conheço o framework… estava me referindo ao padrão mesmo.

mas então… o que o HibernateTemplate faz?

Ele encapsula o código do Hibernate deixando um template para uso… gosto muito pelo fato que não fica aquelas classes como o HibernateUtil…

D
AdemirPinto:
Pessoal,

segui alguns conselhos do pessoal e melhorei bem meu Generic DAO(parte do código abaixo)...muito obrigado a todos.

Só que ainda falta alguns detalhes e dentre eles a questão da Sessão e Transação. Com relação à sessão eu fiz um filter para criar ele e depois em cada requisição eu a recupero, conforme o código abaixo. As dúvidas ainda são:

1)Vocês acham que ficou bom meu HibernateSessionRequestFilter?

2)Estava pensando em fazer o controle de transação nos meus Managed Bean, o que voces acham?

3)No site http://community.jboss.org/wiki/OpenSessioninView tem uma implementação com o controle de transação no filter, isso não é complicado? Tipo eu quero fazer um controle melhorar das minhas exceções para tratar a saida para o usuario. Outra coisa é que ele fica dando beginTransaction e depois commit, mas pode acontecer que a requisição não alterou o banco de dados. O que vocês acham dessa implementação? Vale a pena fazer o controle de transação assim?

HibernateSessionRequestFilter:
public class HibernateSessionRequestFilter implements Filter {
	 
    private SessionFactory sf;
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Throwable ex) {
            ex.printStackTrace();
            throw new ServletException(ex);
        }
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
    	System.out.println("Initializing filter...");
    	System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");
    	sf =  HibernateUtil.getInstace().getSessionFactory();     
    	sf.openSession(); 
    }
 
    public void destroy() {
    	
    }

}
HibernateUtil:
public class HibernateUtil {
	
	private static HibernateUtil me;
	private SessionFactory sessionFactory;

	public HibernateUtil() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}

	public Session getSession() {
		Session toReturn = sessionFactory.openSession();
		return toReturn;
	}

	public static HibernateUtil getInstace() {
		if (me == null) {
			me = new HibernateUtil();
		}
		return me;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
GenericDAO:
@SuppressWarnings("unchecked")
public class GenericDAO<T> {

	@SuppressWarnings("rawtypes")
	private Class persistentClass;
	private Session session;

	//Construtor - ##########################################
	@SuppressWarnings("rawtypes")
	protected GenericDAO(Class p_persistentClass) {
		session = HibernateUtil.getInstace().getSession();		
		persistentClass = p_persistentClass;
	}
	
	public Session getSession() {
		return session;
	}

	@SuppressWarnings("rawtypes")
	public Class getPersistentClassLocal(){
		return persistentClass;
	}
	
	public void insert(T obj) throws Exception {		
		session.save(obj);
		session.flush();
	}

	public void update(T obj) throws Exception {
		session.update(obj);
		session.flush();
	}
	
	public void delete(T obj) throws Exception {
		session.delete(obj);
		session.flush();
	}

	public Integer count(List<Criterion> criterion) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);
			
		for (Criterion c: criterion)
			criteria.add(c);
			
		criteria.setProjection(Projections.rowCount());
		return ((Integer) criteria.uniqueResult()).intValue();
	}

	//Lista todos os registros com ordem e sem limite
	public List<T> listAll(String fieldOrder, SortOrder sortOrder) throws Exception {
		String ord = ConstantesGerais.TIPOORDEMASC; 
		if (sortOrder == SortOrder.DESCENDING)  
			ord = ConstantesGerais.TIPOORDEMDESC;  
			
		Criteria criteria = session.createCriteria(persistentClass);
		addOrder(criteria, fieldOrder, ord);
		return criteria.list();
	}

...

Abraços a todos e um bom FDS.
Ademir

Referente a Sessão e Transação estude Spring:

Transaction Management
[url]http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html[/url]

Outra coisa, use o Spring tambem para evitar o HibernateUtil...

Abraços!

M
AdemirPinto:
Pessoal,

segui alguns conselhos do pessoal e melhorei bem meu Generic DAO(parte do código abaixo)...muito obrigado a todos.

Só que ainda falta alguns detalhes e dentre eles a questão da Sessão e Transação. Com relação à sessão eu fiz um filter para criar ele e depois em cada requisição eu a recupero, conforme o código abaixo. As dúvidas ainda são:

1)Vocês acham que ficou bom meu HibernateSessionRequestFilter?

2)Estava pensando em fazer o controle de transação nos meus Managed Bean, o que voces acham?

3)No site http://community.jboss.org/wiki/OpenSessioninView tem uma implementação com o controle de transação no filter, isso não é complicado? Tipo eu quero fazer um controle melhorar das minhas exceções para tratar a saida para o usuario. Outra coisa é que ele fica dando beginTransaction e depois commit, mas pode acontecer que a requisição não alterou o banco de dados. O que vocês acham dessa implementação? Vale a pena fazer o controle de transação assim?

HibernateSessionRequestFilter:
public class HibernateSessionRequestFilter implements Filter {
	 
    private SessionFactory sf;
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Throwable ex) {
            ex.printStackTrace();
            throw new ServletException(ex);
        }
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
    	System.out.println("Initializing filter...");
    	System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");
    	sf =  HibernateUtil.getInstace().getSessionFactory();     
    	sf.openSession(); 
    }
 
    public void destroy() {
    	
    }

}
HibernateUtil:
public class HibernateUtil {
	
	private static HibernateUtil me;
	private SessionFactory sessionFactory;

	public HibernateUtil() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}

	public Session getSession() {
		Session toReturn = sessionFactory.openSession();
		return toReturn;
	}

	public static HibernateUtil getInstace() {
		if (me == null) {
			me = new HibernateUtil();
		}
		return me;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
GenericDAO:
@SuppressWarnings("unchecked")
public class GenericDAO<T> {

	@SuppressWarnings("rawtypes")
	private Class persistentClass;
	private Session session;

	//Construtor - ##########################################
	@SuppressWarnings("rawtypes")
	protected GenericDAO(Class p_persistentClass) {
		session = HibernateUtil.getInstace().getSession();		
		persistentClass = p_persistentClass;
	}
	
	public Session getSession() {
		return session;
	}

	@SuppressWarnings("rawtypes")
	public Class getPersistentClassLocal(){
		return persistentClass;
	}
	
	public void insert(T obj) throws Exception {		
		session.save(obj);
		session.flush();
	}

	public void update(T obj) throws Exception {
		session.update(obj);
		session.flush();
	}
	
	public void delete(T obj) throws Exception {
		session.delete(obj);
		session.flush();
	}

	public Integer count(List<Criterion> criterion) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);
			
		for (Criterion c: criterion)
			criteria.add(c);
			
		criteria.setProjection(Projections.rowCount());
		return ((Integer) criteria.uniqueResult()).intValue();
	}

	//Lista todos os registros com ordem e sem limite
	public List<T> listAll(String fieldOrder, SortOrder sortOrder) throws Exception {
		String ord = ConstantesGerais.TIPOORDEMASC; 
		if (sortOrder == SortOrder.DESCENDING)  
			ord = ConstantesGerais.TIPOORDEMDESC;  
			
		Criteria criteria = session.createCriteria(persistentClass);
		addOrder(criteria, fieldOrder, ord);
		return criteria.list();
	}

...

Abraços a todos e um bom FDS.
Ademir

o melhor mesmo é você usar algum framework para gerenciar isso, como o spring que nosso amigo citou... eu ja testei uns negocios legais semelhantes a isso com EJB também, o "HibernateUtils" passa a ser desnecessário (ele injeta o seu "gerenciador de conexões" que é semelhante a session do hibernate, da o commit ou rollback automatico... enfim), mas supondo que você não vá usar isso, algumas dicas:

No hibernateUtils, normalmente se diexa o construtor dele privado, para que ninguém consiga instanciar essa classe, para se obter instancias dele deve-se usar um método public static getInstance, para então a partir deste se obter a sessão pelo getSession, ou então nem criar o getInstance, deixando o getSession estatico também para ser acessivel de fora do objeto (eu gosto de fazer dessa forma ja que este é o unico método que deixo acessivel nessa classe). Não deixo getters e setters do seu SessionFactory, classes de fora não deveriam acessa-lo, apenas a própria classe de dentro para criar sessões, se você tiver deixado o getSession estático, você deixaria também o sessionFactory estático inicializaria ele em um bloco também estatico.

Veja esse exemplo, estou sem ide, podem ter erros de digitação e por isso não compilar:

public class HibernateUtil {  
      
    private static HibernateUtil me;  
    private static SessionFactory sessionFactory;  
  
    static {  
        sessionFactory = new Configuration().configure().buildSessionFactory();  
    }  
  
    public static Session getSession() {  
        Session toReturn = sessionFactory.openSession();  
        return toReturn;  
    }  
        
}

o formato do padrão singleton normalmente é aquele que expliquei, construtor privado, uma instancia de si própria usado no getInstance (do jeito que você estava usando), e ai o getSession, seria o mesmo que você estava fazendo sem permitir acesso ao sessionFactory e com o construtor privado, mas acho que desse jeito é melhor, não precisa ficar chamando getInstance e não tem por que trabalhar com objetos neste caso.

O seu filter também não está 100 %, repare que sua sessão nunca é fechada, nem disponibilizada de alguma forma para o modelo, desse jeito não sei como você obteria ela no seu modelo, vocÊ ainda precisaria chamar o hibernateUtils la, sendo que esse filtro é justamente para vocÊ não fazer isso, veja o exemplo abaixo:

ps. editei por que vi que do jeito que estava a sessão ficaria fora de escopo na hora de fechar...

public class HibernateSessionRequestFilter implements Filter {  
    
	public static String HIBERNATE_SESSION_NAME = "sessao_hibernate";
	
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        Session s = null;
        try {
			//prefira usar algum log de verdade para isso	
			System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");  
			s = HibernateUtil.getSession();
			HttpSession httpSession = ((HttpServletRequest) request).getSession(true);
			httpSession.setAttribute(HIBERNATE_SESSION_NAME, s);
			
            chain.doFilter(request, response);  
        } catch (Throwable ex) {  
            ex.printStackTrace();  
            throw new ServletException(ex);  
        }

		try {
			if (s != null) s.close();
        } catch (Throwable ex) {  
			//logar aqui
            ex.printStackTrace();  
        }
    }  
  
    public void init(FilterConfig filterConfig) throws ServletException {  
          
    }  
  
    public void destroy() {  
          
    }  
  
}

assim no seu modelo você pegaria sua sessão e obteria a sessão do hibenrate na sessão pelo nome chapado na constante existente no filtro.

a, mesmo que vocÊ use algum framework, é interessante você entender este conceito...

editando denovo... agora que eu vi seu item 2... se você colocar o gerenciamento das transações no controller, ai o seu modelo fica +- dependente dele. O ideal é você desacoplar ao máximo as camadas... vamos a um exemplo: se o seu cliente quiser portar a aplicação que está sendo feita de web para destop por exemplo, como você está desenvolvendo em camadas e tem uma camada de modelo na aplicação web, pode pode colocar essa camada interinha na aplicação desktop certo? ai no controller da sua aplicação desktop você só chama o modelo e ele ja faz tudo o que tem que fazer... estranhamente o modelo para inserir clientes (exemplo) não loga nenhum erro, a aplicação fala que cadastrou com sucesso mas o dado não ta la na base... depois de muito analisar o código você vê que não commitou, isso por que o commit ou rollback ficaria no controller, você não copiou o controller e esqueceu de re-escrever isso na app desktop. Ja descobrimos ai dois problemas, o primeiro é que uma camada tem certa dependencia da camada acima, o que não é o ideal, o segundo problema é que você está re-escrevendo código. Se você tivesse colocado isso no modelo la certiho, não teria nenhum destes problemas. Sim dessa forma leva um pouco mais de tempo e da um pouco mais de trabalho... no desenvolvimento do software, mas com certeza você terá menos trabalho e gastará menos tempo na manutenção (seja por correções, seja por alterações), e acredite, o normal é gastar mais tempo na manutenção de um software do que na construção...

a se la para frente alguém decidir alterar o framework mvc você terá os mesmos problemas que no exemplo que eu citei.

nessa thread, que é de outro assunto mais ai o assunto mudou para "colocar o modelo no managed bean do jsf", eu tentei explicar resumidamente o por que de isso ser uma ideia ruim...

A

Fala maior_abandonado, como te falei to quase chegando lá.

Me fala uma coisa na linha 10 da classe HibernateSessionRequestFilter vc tem “s = HibernateUtil.getSession();”, pq vc nao usa isso na init do HibernateSessionRequestFilter?
Pq no http://community.jboss.org/wiki/OpenSessioninView o getSessionFactory() fica na init?

Abraços
Ademir

M

bom… vamos primeiro ao conceito de quando estes métodos são chamados:

O init é chamado quando a filter é iniciada, colocada em funcionamento.

o destroy é chamado quando a filter é retirada do funcionamento.

o doFilter é chamado sempre que ocorre uma requisição. Quando você chama o filter.chain é passada para frente a requisição, de forma que o código que você deixar antes disso executa antes da requisição prosseguir para o que quer que ela tenha interceptado, o que você codificar depois disso vai acontecer depois da requisição terminar.

eu nem tenho certeza se eu tinha te explicado a ideia do open session in view, a ideia é a seguinte, quando o usuário vai requisitar uma página, você abre a sessão, usa ela para tudo o que tiver que fazer ali para aquela requisição do usuário e depois de ter feito isso fecha essa sessão. Por isso estou abrindo a sessão no doFilter antes de chamar o chain e fechando depois de chama-lo, para fazer oq ue descrevi acima. Supomos que nós abrissemos a sessão no init e os managed beans usassem ela (supondo que você tivesse disponibilizado ela para seus managed beans ali por exemplo. Todas as requisições de todos os usuários usariam essa mesma sessão, inclusive requisições concorrentes estariam usando a mesma sessão (isso não é bom). De qualquer forma feito isso, se vocÊ abrir sua sessão no innit vocÊ deverá fecha-la no destroy (você sempre deve fechar sua sessão/conexão com o banco/devolver recursos que estiver usando).

A

Fala maior_abandonado,

saquei o que vc disse. Achava que o init era por sessão(http) de usuário e nao para todas as sessões. Uma outra dúvida, fiz a minha segurança no PhaseListener, mas será que não seria melhor no Filter? Pesquisei na net e aqui no forum, mas as opiniões são divergentes. Não existe um evento que é disparado por nova sessão http?
A propriedade do Hibernate “hibernate.current_session_context_class” deve ser managed ou thread para open session in view?

Qnd tiver redondinho aqui vou compartilhar os fontes pro pessoal ter acesso.

Grande abraços e mais uma vez muito obrigado.
Ademir

M

quanto a usar o PhaseListener ou a Servlet Filter, eu acredito no seguinte: se você conhecer bem como funcionam as fases do jsf e souber assim usar bem o PhaseListener, tanto faz… simples assim, então se é uma coisa que vai ser verificada em qualquer requisição por exemplo e apenas uma vez a cada requisição, eu prefiro filter unicamente por que é masi facil… isso é um gosto pessoal, cada um pode preferir de uma forma, porém se você quer alguma outra coisa especifica para o jsf, especialmente se for em uma das fases da requisição do jsf, ai phaseListener é mais indicado. Use aquele que vocÊ se sentir mais seguro.

quanto ao “hibernate.current_session_context_class”, não costumo configurar isso, fiquei sabendo o que é agora :roll:. Dei uma pesquisada e aqui estão indicando usar managed.

G

Na verdade, pode-se até desconsiderar o uso do Filter do Servelet usando o PhaseListener do JSF, uma coisa pode substituir a outra. Apesar que até hoje, só encontrei aplicações feitas usando o Filter mesmo.

A

Pessoal,

depois de pesquisar muito e principamente da ajuda deste forum estou liberando minhas classes: SessionFactoryUtil, HibernateSessionUtil, HibernateSessionFilter e GenericDAO.
O projeto é web e usando Open Session View. Por enquanto não estou usando IoC e nem Spring já que estou iniciando no mundo java.
Gostaria da avaliação e críticas de vcs não usando IoC e nem Spring. A versão do meu hibernate é 3.6.
Estou compartilhando o meu código para quem quiser copiar sem necessidade de referenciar origem.

Grande abraço e fiquem com Deus.

Ademir

public class SessionFactoryUtil {

	private static final SessionFactory sessionFactory;

	static {
		try {
			sessionFactory = new Configuration().configure().buildSessionFactory();
		} catch (Throwable e) {
			GravaLogErro.SalvarLogErro(e, "SessionFactoryUtil - Inicialização do SessionFactory");
			throw new ExceptionInInitializerError(e);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

}
public final class HibernateSessionUtil {
	
	public HibernateSessionUtil() {	
				
	}

	public static Session getSession() {  
		return SessionFactoryUtil.getSessionFactory().getCurrentSession();
	}
	
	public static boolean isOpen() {
		return getSession().isOpen();
	}
	
	public static boolean inTransaction() {
		return getSession().getTransaction().isActive();
	}

	public static void beginTransaction() {
		if (!inTransaction())
			getSession().beginTransaction();
	}

	public static void commitTransaction() {
		if (inTransaction())
			getSession().getTransaction().commit();
	}

	public static void rollbackTransaction() {
		if (inTransaction())
			getSession().getTransaction().rollback();
	}

}
public class HibernateSessionFilter implements Filter {

    private SessionFactory sf;
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        Session session;
        
        try {            
            session = sf.openSession();
            
            ManagedSessionContext.bind((org.hibernate.classic.Session) session);
            session.setFlushMode(FlushMode.AUTO);
            
            chain.doFilter(request, response);
                 
            session = ManagedSessionContext.unbind(sf);
            
            if (HibernateSessionUtil.inTransaction()) {
            	//Gravar Log de problema
            }
            
            try {
				if ((session != null) && (session.isOpen())) {					
					session.close();					
				} else {
					//Gravar Log de problema
				}
			} catch (Throwable e) {
				GravaLogErro.SalvarLogErro(e, "doFilter ERROR - CloseSession");
			}            
            
        } catch (Throwable t) {
            try {
            	GravaLogErro.SalvarLogErro(t, "doFilter ERROR");
            	if (HibernateSessionUtil.inTransaction()) {
            		HibernateSessionUtil.rollbackTransaction();
                }
            } catch (Throwable rbT) {
            	//Gravar Log de problema
            } 
            
            finally {               
                session = ManagedSessionContext.unbind(sf);
                session.close();
            }
            
            throw new ServletException(t);
        }
        
    }
    
    public void init(FilterConfig filterConfig) throws ServletException {
    	try {
    		sf = SessionFactoryUtil.getSessionFactory();
    	} catch (Throwable rbT) {
        	//Gravar Log de problema
        }	
    }
    
    public void destroy() {
    	
    }
    
}
public class GenericDAO<T> {

	private Class persistentClass;
	private Session session;

	protected GenericDAO(Class p_persistentClass) {
		session = HibernateSessionUtil.getSession();
		persistentClass = p_persistentClass;
	}

	public Session getSession() {
		return session;
	}

	public Class getPersistentClassLocal(){
		return persistentClass;
	}

	public void insert(T obj) throws Exception {
		session.save(obj);
		session.flush();
	}

	public void update(T obj) throws Exception {
		session.update(obj);
		session.flush();
	}

	public void saveOrUpdate(T obj) throws Exception {
		session.saveOrUpdate(obj);
		session.flush();
	}

	public void merge(T obj) throws Exception {
		session.saveOrUpdate(obj);
		session.flush();
	}

	public void delete(T obj) throws Exception {
		session.delete(obj);
		session.flush();
	}

	public Integer count(List<Criterion> criterion) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);

		for (Criterion c: criterion)
			criteria.add(c);

		criteria.setProjection(Projections.rowCount());
		return ((Integer) criteria.uniqueResult()).intValue();
	}

	public List<T> listAll(String fieldOrder, SortOrder sortOrder) throws Exception {
		String ord = ConstantesGerais.TIPOORDEMASC;
		if (sortOrder == SortOrder.DESCENDING)
			ord = ConstantesGerais.TIPOORDEMDESC;

		Criteria criteria = session.createCriteria(persistentClass);
		addOrder(criteria, fieldOrder, ord);
		return criteria.list();
	}

	public List<T> listAll(int first, int max, String fieldOrder, SortOrder sortOrder, List<Criterion> criterion) throws Exception {
		String ord = ConstantesGerais.TIPOORDEMASC;
		if (sortOrder == SortOrder.DESCENDING)
			ord = ConstantesGerais.TIPOORDEMDESC;

		Criteria criteria = session.createCriteria(persistentClass);
		addOrder(criteria, fieldOrder, ord);

		for (Criterion c: criterion)
			criteria.add(c);

		if (first != 0)
			criteria.setFirstResult(first - 1);

		if (max != 0)
			criteria.setMaxResults(max);

		return criteria.list();
	}

	public T findById(Long id) throws Exception {
		return (T) session.get(persistentClass, id);
	}

	public String findByColumn(Long id, String fieldReturn) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);
		criteria.add(Restrictions.eq(getFieldId(), id)).setProjection(Projections.property(fieldReturn));
		criteria.uniqueResult();
		if (criteria.uniqueResult() == null)
			return "";
		else
			return criteria.uniqueResult().toString();
	}

	public String findByColumnValue(String findColumn, Long findValue, String fieldReturn) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);
		criteria.add(Restrictions.eq(findColumn, findValue)).setProjection(Projections.property(fieldReturn));
		if (criteria.uniqueResult() == null)
			return "";
		else
			return criteria.uniqueResult().toString();
	}

	public List<T> findByCriteria(List<Criterion> criterion) throws Exception {
		Criteria criteria = session.createCriteria(persistentClass);

		if (criterion == null)
			return null;

		for (Criterion c: criterion)
			criteria.add(c);

		return criteria.list();
	}

	private Criteria addOrder(Criteria criteria, String fieldOrder, String ord) {
		if (!fieldOrder.isEmpty()) {
			if ((ord.toUpperCase().equals("ASC")) || (ord.isEmpty()))
				criteria.addOrder(Order.asc(fieldOrder));

			if (ord.toUpperCase().equals("DESC"))
				criteria.addOrder(Order.desc(fieldOrder));
		}
		return criteria;
	}

}
A

up

E

Pra quem está usando spring, conhecem o projeto spring-data? Chamava-se HADES e foi incorporado pelo Spring. Estou estudando ainda, e não sei se aquilo pode ser chamado de Repository (se é que a intenção foi vincular ao pattern da Domain Driven Design), mas me pareceu bem prático. Estou usando em um projeto e funciona direitim :slight_smile:

http://www.springsource.org/spring-data

Outra grande vantagem é que ele faz a abstração da tecnologia de persistência, que pode ser até bancos NoSQL, como MongoDB.

M

Normalmente, defino meu DAO como sendo uma interface, e crio uma classe de implementação para o mesmo.

Criado 7 de julho de 2011
Ultima resposta 28 de set. de 2011
Respostas 35
Participantes 10