Duvidas no Hibernate [Resolvido]

7 respostas
gustavotorquato

Ola pessoal, tenho duvidas quanto a session no hibernate, sou iniciante, entao tenham paciencia, kkkkk.

Bom, ai vao minhas duvidas:

  1. A cada operação preciso pegar a sessao, executar a operação, da um flush na sessao e depois fecha-la e depois dar um comit?

  2. no caso do commit, posso fazer varias operações, abrindo e fechando sessoes e apenas depois da um commit?

  3. e na Transaction, a cada operação (tipo de insert, update ou delete) preciso criar uma transaction nova, ou posso criar apenas um e usar em todas as operações.

Obrigado.

7 Respostas

M

R1: Bem, sim vc precisa sempre de uma sessão para poder conectar com o banco, o fluch não é necessário se vc esta trabalhando com um commite para cada operação (isso pode causar alguns bugs em aplicações web, para facilitar dê uma olhada em uma padrão chamado opensessioninview), caso não vc precisa da o flush, como disse anteriormente, se vc estiver trabalhando com um commit para cada operação vc tem que dar o commit antes de fecha a sessão.

R2: Como eu disse, não… vc tem que abrir a sessão para poder abrir uma transação e assim poder dar commit.

R3: Transação é uma cosia atômica, então sempre que vc estiver fazendo uma operação vc vai ter sim que abrir UMA transação e fecha-la.

drsmachado

1 - Flush não é necessário, mas, para todas as operações que alteram o conteúdo das tabelas, você precisará do commit.

2 - Sim e não. Sim se forem todas na mesma transação (ex, salvar vários itens de uma lista). Não se você tentar fazer isto após fechar a sessão. O problema em se fazer muitas coisas e depois de todas prontas confirmá-las (commit) é que, caso alguma delas não seja executada com sucesso (lance exception) e você dê rollback, perderá todas as que foram realizadas de forma adequada.
Se você procurar qualquer dao genérico na internet, verá que cada método (insert, update e delete) vão criar uma nova instância de session e de transaction. Alguns até utilizam uma espécie de singleton para a session, mas, a transaction, sempre será uma nova instância.

3 - Não, você pode criar apenas uma transaction por sessão, mas, a cada commit, precisará renovar a Transaction (instanciá-la novamente). Desde que a session não tenha sido fechada.

gustavotorquato

entao pessoal, muito obrigado pelas resposta. Vou citar um exemplo aqui.

Uma operação com um produto qualquer:

  • Crio uma sessao apenas
  • Crio uma transaction
  • Chamo o metodo para buscar o produto
  • altero alguns atributos do produto
  • chamo o metodo para alterar o produto
  • chamo um metodo para criar um outro produto
  • no final de tudo, dou um commit
  • fecho a sessao

Minha duvida maior é essa, posso fazer varias operações dentro de uma session apenas e no final de tudo dar um commit?

gustavotorquato

Vejam minha classe GenercDAO

package sel.dao;

import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import sel.persistencia.Conexao;

public abstract class GenericDAO<T> {
	
	protected Logger log = Logger.getLogger("desenvolvimento");
	protected Session session;
	protected Transaction tx;
	protected Boolean sucesso = new Boolean(false);
	
	
	public Boolean salvarOuAlterar(T obj) {
		log.debug("PERSISTINDO objeto da classe: "+obj.getClass());
		session = Conexao.getInstance();
		
		try{
			tx = session.beginTransaction();
			session.saveOrUpdate(obj);
			session.flush();
			sucesso = true;
			log.debug("Objeto da classe "+obj.getClass()+" PERSISTIDO com sucesso!");
		} catch(Exception e) {
			tx.rollback();
			sucesso = false;
			log.debug("Ocorreu um erro ao PESISTIR o objeto da classe: "+obj.getClass());
			log.error("Classe GenericDAO --- Erro no método salvarOuAlterar(): "+e);
			e.printStackTrace();
		} finally {
			session.close();
		}
		
		return sucesso;
	}
	
	public Boolean remover(T obj) {
		log.debug("REMOVENDO objeto da classe: "+obj.getClass());
		session = Conexao.getInstance();
		
		try{
			tx = session.beginTransaction();
			session.delete(obj);
			session.flush();
			sucesso = true;
			log.debug("Objeto da classe "+obj.getClass()+" REMOVIDO com sucesso!");
		} catch(Exception e) {
			tx.rollback();
			sucesso = false;
			log.debug("Ocorreu um erro ao REMOVER o objeto da classe "+obj.getClass());
			log.error("Classe GenericDAO --- Erro no metodo remover(): "+e);
			e.printStackTrace();
		} finally {
			session.close();
		}
		
		return sucesso;
	}
	
	public Object buscarPorId(String nomeClasse, Integer pk) {
		log.debug("BUSCANDO objeto da classe: "+nomeClasse+" pelo id: "+pk);
		session = Conexao.getInstance();
		Object obj = null;
		
		try{
			tx = session.beginTransaction();
			obj = session.load(nomeClasse, pk);
			log.debug("BUSCA do objeto da classe "+nomeClasse+" executada com sucesso!");
		} catch(Exception e) {
			log.debug("Ocorreu um erro ao BUSCAR o objeto da classe: "+nomeClasse);
			log.error("Classe GenericDAO --- Erro no metodo buscarPorId(): "+e);
			e.printStackTrace();
		} finally {
			session.close();
		}
		
		return obj;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> buscarTodos(String nomeClasse) {
		log.debug("BUSCANDO todos os registros da classe: "+nomeClasse);
		session = Conexao.getInstance();
		Query query = session.createQuery("from "+nomeClasse); 
		List<T> lista = null;
		
		try{
			log.debug("BUSCA geral da classe "+nomeClasse+" executada com sucesso!");
			tx = session.beginTransaction();
			lista = query.list();
		} catch(Exception e){
			log.debug("Ocorreu um erro ao BUSCAR os registros da classe: "+nomeClasse);
			log.error("Classe GenericDAO --- Erro no metodo buscarTodos(): "+e);
			e.printStackTrace();
		} finally{
			session.close();
		}
		
		return lista;
	}
	
	public Integer quantidadeRegistros(String nomeClasse) {
		log.debug("BUSCANDO quantidade de registros da classe: "+nomeClasse);
		Integer quantidade = new Integer(0);
		session = Conexao.getInstance();
		Query query = session.createQuery("from "+nomeClasse); 
		
		try{
			log.debug("BUSCA de quantidade de registros da classe "+nomeClasse+" executada com sucesso!");
			tx = session.beginTransaction();
			quantidade = query.list().size();
		} catch(Exception e){
			log.debug("Ocorreu um erro ao TOTALIZAR os registros da classe: "+nomeClasse);
			log.error("Classe GenericDAO --- Erro no metodo quantidadeRegistros(): "+e);
			e.printStackTrace();
		} finally{
			session.close();
		}
		
		return quantidade;
	}
	
	public void executar() {
		tx.commit();
	}
}

A partir desta classe, tenho outras classes DAO especifica para extende-la, por exemplo:

UsuarioDAO

package sel.dao;

import org.hibernate.Query;

public class UsuarioDAO extends GenericDAO<Object>{

	public Object validarUsuario(String login, String senha) {
		Object obj = null;
                session = Conexao.getInstance();
		try {
			tx = session.beginTransaction();
			Query q = session.getNamedQuery("Usuario.validar");
			q.setString("login", "gustavo.costa");
			q.setString("senha", "123");
			obj = q.uniqueResult();
			session.flush();
		} catch(Exception erro) {
			System.out.println(erro);
			tx.rollback();
		} finally{
			session.close();
		}
		
		return obj;
	}
}
drsmachado

Sim, pode.
Mas como te disse, se ocorrer um erro em alguma delas, como fará para tratar isto?
Sinceramente, sugiro utilizar conforme orientamos, para cada execução (insert, update ou delete) um commit específico.

gustavotorquato

Blz pessoal, ja estou implementando isso, muito obrigado por tudo.

M

Faz assim:

1 - Recupera ou cria a sessão;

2 - Cria a transação;

3 - Executa [color=red]UMA OPERAÇÃO[/color]

4 - Finalização;

4.1 - [color=red]Se não deu falha Commit[/color];

4.2 - [color=red]Se deu falha rollback[/color]

5 - Finaliza a transação;

6 - Finaliza a sessão.

Bem esse é um passo-a-passo de como faz [color=red]UMA OPERAÇÃO[/color]. Espero que te ajude cara! Quanto ao GenericDao tá tudo certo!
Aconselho mais uma vez de vc da uma sacada no OpenSessioInView! Principalmente se vc estiver com um projeto web!

Criado 13 de janeiro de 2012
Ultima resposta 13 de jan. de 2012
Respostas 7
Participantes 3