Controlando as transacoes no hibernate

Gostaria de saber uma boa maneira de controlar as transacoes do hibernate. Hoje eu faco isso manualmente em uma classe de negocio da seguinte maneira:

public class LoginBO{
	public Login makeLoginPersistent(Login login) throws Throwable{
		try{
			HibernateHelper.beginTransaction();
			LoginDAO loginDAO = factory.getLoginDAO();
			login = loginDAO.makePersistent(login);
			HibernateHelper.commitTransaction();
		} catch (Throwable e) {
			HibernateHelper.rollbackTransaction();
			throw e;
		}
		
		return login;
	}
	....
}

Isso gera uma pouco de transtorno pois gera muito codigo repetitivo, eu tentei usar uma abordagem usando Anotacoes conforme este tutorial:
http://www.guj.com.br/java.tutorial.artigo.182.1.guj

Essa solucao pra mim tava otima, mas depois que comecei a “debugar” verifiquei que varias transacoes eram abertas e fechadas sem muito sentido.

Se alguem tiver uma dica por favor postem abaixo.
Desde ja muito obrigado

Você tentou entender porque estas transações estavam sendo abertas? :wink:

Uma coisa bem legal de se fazer que pode ser uma alternativa pra você é controlar as transações com AOP: http://www.hibernate.org/115.html

Abraços,
Guilherme Chapiewski

Tentei… mas esses componetes que fazem uso do CGLIB sao confusos, segue abaixo parte da minha implementacao

/**
 * Cerne do componente para controle de transacao. Faz uso de CGLib, 
 * uma biblioteca que provê mecanismos de manipulação de bytecode, permitindo 
 * implementar interfaces dinamicamente, interceptar a chamada de métodos.
 * Chamando determinado método, interceptamos a sua ação, e verificamos se este método
 * é transacional. Se for, abrimos uma transação, e executamos o método. 
 * Se ele for executado com sucesso, damos commit na operação. 
 * Porém, se der exceção, fazemos um rollback
 * 
 * Isso se parece com a solução de Filtros Http, porém com uma vantagem: 
 * o controle transacional não fica misturado com a API do Controller (C do padrão MVC), 
 * e é mais flexível, pois não se prende ao contexto web
 * 
 * Observe também que esta solução é melhor que tratar as transações diretamente nas classes Java. 
 * Isso porque você vai evitar muito código repetitivo (try, catch, commit, rollback, etc), 
 * e não vai ?poluir? inúmeras classes com este tipo de código.
 * @author Ronildo
 */
public abstract class HibernateInterceptor implements MethodInterceptor {
	
	private static final Logger logger = Util.startLogger(HibernateInterceptor.class);

	/**
	 * O método intercept, proveniente da interface MethodInterceptor (CGLib), se encarrega 
	 * de fazer o controle transacional. Veja que ele usa o HibernateHelper, 
	 * e que o método transacional é explicitamente invocado, através de methodProxy.invokeSuper(), 
	 * e o seu retorno é explicitamente devolvido
	 * @throws Throwable 
	 */
	public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable  {
		
		if (isTransactional(object, method)){
			logger.debug("logica de negocio deve ser executada dentro de uma transacao");
			HibernateHelper.beginTransaction();
		}
		
		Object result = null;
		try {
			result = methodProxy.invokeSuper(object, args);
			HibernateHelper.commitTransaction();
			logger.debug("logica de negocio executada com sucesso");
		}catch (Throwable e){
			logger.debug("erro ao executar logica de negocio");
			HibernateHelper.rollbackTransaction();
			throw e;
		}
		
		return result;
	}
	
	
	/**
	 * Definido como abstrato para para obter máxima flexibilidade, pois apenas 
	 * estendendo esta classe e implementando este método, podemos saber se o 
	 * método é transacional ou não de diversas maneiras, como arquivos XML, 
	 * arquivos texto, e anotações! (Esta classe é um caso do pattern Template Method).
	 */
	public abstract boolean isTransactional(Object object, Method method) ;
}

Eu nao entendo o momento em que o commit sera executado, parece que a rotina para depois de methodProxy.invokeSuper(object, args); e depois sem muito sentido ela e executada

Olá Ronildo,

Acho que já troquei emails com você, não?

O methodProxy.invokeSuper(object, args) invoca o método “de verdade”! E logo depois de terminar a execução dele haverá o commit.

Agora quanto a muitas transações abertas e fechadas… é uma transação por anotação. Tome cuidado para por a anotação no lugar adequado: geralmente em um façade para as operaões, por exemplo.

Abraço