Escopo @prototyped e commit de banco

Pessoal estou com o seguinte problema que não estou entendendo muito bem…

Tenho um componente que está anotado como @PrototypedScope abaixo



 package br.com.webtia.contrato.daos;

 
 import java.util.List;

import javax.annotation.PreDestroy;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.PrototypeScoped;
import br.com.webtia.contrato.models.Configuracao;

 @Component 
 @PrototypeScoped
 public class ConfiguracaoDao {

	 private Session session;
		
		public ConfiguracaoDao(SessionFactory sessionFactory) {
			this.session = sessionFactory.openSession();
		}

		 @SuppressWarnings("unchecked")
		 public List<Configuracao> listAll(Integer firstResult,Integer maxResults){
			 Query query=this.session.getNamedQuery("listAllConfiguracao");
			 query.setString("ativo","S");
			 if(firstResult!=null&&maxResults!=null){
				 query.setFirstResult(firstResult).setMaxResults(maxResults);
			 }
			 return query.list();
		 }

		 public Configuracao load (Long id){
			 return (Configuracao) this.session.load(Configuracao.class,id);
		 }

		 public void insert (Configuracao configuracao){
			 this.session.save(configuracao);
		 }

		 public void update (Configuracao configuracao){
			 this.session.merge(configuracao);
		 }

		 public void delete (Configuracao configuracao){
			 this.session.delete(configuracao);
		 }
		 
		 public String getVariableByModuleName(String module,String variable){
			 Query query=this.session.getNamedQuery("getVariableByModuleName");
			 query.setString("modulo",module);
			 query.setString("variavel",variable);
			 return (String) query.uniqueResult();
		 }
		 
		 public Integer count() {
				Query query=this.session.getNamedQuery("countAllConfiguracao");
				query.setString("ativo","S");
				return ((Long)query.uniqueResult()).intValue();
		}
 }

Quando utilizo qualquer método de persistencia no banco Oracle10g ele não realiza a modificação…
ele não retorna erro da aplicação …o debug do hibernate imprime

jdbc : commit
jdbc : commited

mas não é realizado…

por padrão o vraptor da o session.close() usando esse tipo de escopo??

pois pelo que vi o hibernatecustomprovider fica em escopo de request …alguma ideia???

Onde está sua transação? Onde você faz um flush? E onde você fecha a session? O Vraptor por sí próprio não vai fazer nada porque você está injetando a SessionFactory. O correto é usar a Session.

Porque ao invés de reinventar a coisa você não usa o componente do Vraptor que faz todo esse controle de abrir/fechar sessions e transaction?

Qual é o motivo pra esse dao ser Prototype?

a regra é: se você abriu a sessão, você fecha…

ou seja, se a ConfiguracaoDao abriu, ela fecha. Possivelmente criar uma metodo close() anotado com @PreDestroy funcione… não sei se isso rola no @PrototypeScoped, mas nos outros escopos sim…

e de qqer forma, pra modificar coisas do banco, a operação deve estar dentro de uma transação, senão não acontece nada

[quote=garcia-jj]Onde está sua transação? Onde você faz um flush? E onde você fecha a session? O Vraptor por sí próprio não vai fazer nada porque você está injetando a SessionFactory. O correto é usar a Session.

Porque ao invés de reinventar a coisa você não usa o componente do Vraptor que faz todo esse controle de abrir/fechar sessions e transaction?[/quote]

br.com.caelum.vraptor.provider br.com.caelum.vraptor.util.hibernate.HibernateCustomProvider

Ja estou usando o HibernateCustomProvider.Não estou “reinventando a coisa”…preciso de @prototyped scope pq utilizo dao numa job scheduler…e nao consigo injetar componente em escopo de request no caso essa DAO…

[quote=Lucas Cavalcanti]Qual é o motivo pra esse dao ser Prototype?

a regra é: se você abriu a sessão, você fecha…

ou seja, se a ConfiguracaoDao abriu, ela fecha. Possivelmente criar uma metodo close() anotado com @PreDestroy funcione… não sei se isso rola no @PrototypeScoped, mas nos outros escopos sim…

e de qqer forma, pra modificar coisas do banco, a operação deve estar dentro de uma transação, senão não acontece nada[/quote]

Bom o motivo dele ser prototyped é de poder injetar ele em um componente job scheduler…que fica em escopo de application…a injecao funciona sem o spring reclamar…so que fica esse problema do close…

Bom como estou usando o componente de voces o “HibernateCustomProvider” ele ja nao usa por padrão a abertura e fechamento da transação com o HibernateTransactionInterceptor ?? ou so faz isso em escopo de request??

Tentei criar um @preDestroy num metodo chamado close do dao mas ele nunca é chamado :frowning: …alguma ideia de como fazer um close dessa session???

Bom resolvi de um modo bem feio viu …tendo que abrir e fechar transação na mão e a session tb.

package br.com.jslsolucoes.jgenerator.daos;

import java.util.Calendar;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.PrototypeScoped;
import br.com.jslsolucoes.jgenerator.models.EmailPanel;

@Component
@PrototypeScoped
public class EmailPanelDao {

	private Session session;

	public EmailPanelDao(SessionFactory sessionFactory) {
		this.session = sessionFactory.openSession();
	}

	@SuppressWarnings("unchecked")
	public List<EmailPanel> listAll(Integer firstResult, Integer maxResults) {
		Criteria criteria = this.session.createCriteria(EmailPanel.class);
		criteria.add(Restrictions.eq("active", "S"));
		if (firstResult != null && maxResults != null) {
			criteria.setFirstResult(firstResult).setMaxResults(maxResults);
		}
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	public List<EmailPanel> listAllNotSended() {
		Criteria criteria = this.session.createCriteria(EmailPanel.class);
		criteria.add(Restrictions.eq("active", "S"));
		criteria.add(Restrictions.eq("sended", "N"));
		return criteria.list();
	}

	public String saveOrUpdate(EmailPanel emailpanel) {
		if (emailpanel.getId() == null) {
			this.insert(emailpanel);
			return "insert";
		} else {
			this.update(emailpanel);
			return "update";
		}
	}

	public EmailPanel load(Long id) {
		return (EmailPanel) this.session.load(EmailPanel.class, id);
	}
	
	public void insert(EmailPanel emailpanel) {
		emailpanel.setInclusiondate(Calendar.getInstance().getTime());
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			this.session.save(emailpanel);
			transaction.commit();
		} finally {
			if (transaction != null && transaction.isActive()) {
				transaction.rollback();
			}
			this.session.close();
		}		
	}

	public void update(EmailPanel emailpanel) {
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			this.session.merge(emailpanel);
			transaction.commit();
		} finally {
			if (transaction != null && transaction.isActive()) {
				transaction.rollback();
			}
			this.session.close();
		}		
	}

	public void delete(EmailPanel emailpanel) {
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			this.session.delete(emailpanel);
			transaction.commit();
		} finally {
			if (transaction != null && transaction.isActive()) {
				transaction.rollback();
			}
			this.session.close();
		}		
	}

	public void deactive(String ids) {
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			for (String id : ids.split(",")) {
				EmailPanel emailpanel = this.load(new Long(id));
				emailpanel.setActive('N');
			}
			transaction.commit();
		} finally {
			if (transaction != null && transaction.isActive()) {
				transaction.rollback();
			}
			this.session.close();
		}
	}

	public Integer count() {
		Criteria criteria = this.session.createCriteria(EmailPanel.class);
		criteria.setProjection(Property.forName("id").count());
		criteria.add(Restrictions.eq("active", "S"));
		return ((Long) criteria.uniqueResult()).intValue();
	}
}

Teria outro jeito mais elegante ja que utilizo diversos componentes com a anotação @prototyped nas tarefas agendadas???

esses daos anotados com @PrototypeScoped são usados só nas tarefas agendadas, ou em todo o sistema?

todo o sistema…ou seja …ele teria que rodar na aplicação em escopo de request e teria que ser reaproveitado nas tarefas agendadas…

um jeito fácil de fazer é:

  • deixe todos os seus daos request scoped mesmo

  • crie um componente assim:

@Component
@ApplicationScoped
public class DaoManager { // ou interface-implementação se preferir

    private Map<Dao, Session> daos = new HashMap<...>(); // ou alguma abstração disso

    public DaoManager(SessionFactory factory) {
         this.factory = factory;
    }

    public <T extends Dao> T createDao(Class<T> daoType) {
        //abre uma sessao
        //abre uma transacao
        //instancia o dao
        //coloca o dao no mapa, ligado com a sessao dele (talvez com a transacao tb, se vc criar uma classe que engloba isso)
        //retorna o dao
    }

    public void destroyDao(Dao dao) {
        //pega a sessao do dao no mapa
        //commita ou dá rolllback na transacao
        //fecha a sessao
    }
}

e na tarefa agendada vc usaria o DaoManager abrindo e fechando o dao

existem várias maneiras de melhorar isso…

outros jeitos envolvem criar aspectos, proxies, ou coisas do tipo

[quote=Lucas Cavalcanti]um jeito fácil de fazer é:

  • deixe todos os seus daos request scoped mesmo

  • crie um componente assim:

@Component
@ApplicationScoped
public class DaoManager { // ou interface-implementação se preferir

    private Map<Dao, Session> daos = new HashMap<...>(); // ou alguma abstração disso

    public DaoManager(SessionFactory factory) {
         this.factory = factory;
    }

    public <T extends Dao> T createDao(Class<T> daoType) {
        //abre uma sessao
        //abre uma transacao
        //instancia o dao
        //coloca o dao no mapa, ligado com a sessao dele (talvez com a transacao tb, se vc criar uma classe que engloba isso)
        //retorna o dao
    }

    public void destroyDao(Dao dao) {
        //pega a sessao do dao no mapa
        //commita ou dá rolllback na transacao
        //fecha a sessao
    }
}

e na tarefa agendada vc usaria o DaoManager abrindo e fechando o dao

existem várias maneiras de melhorar isso…

outros jeitos envolvem criar aspectos, proxies, ou coisas do tipo[/quote]

obrigado lucas vou tentar melhorar as classes…

 public <T extends Dao> T createDao(Class<T> daoType) {
        //abre uma sessao
        //abre uma transacao
        //instancia o dao
        //coloca o dao no mapa, ligado com a sessao dele (talvez com a transacao tb, se vc criar uma classe que engloba isso)
        //retorna o dao
    }

como faço a instancia desse generic??

 public <T extends Dao> T createDao(Class<T> daoType) {
        Session session = factory.openSession();
        Transaction transaction = session.beginTransaction();
        // T dao = ?????;
        dao.put(dao,session);
        return dao;
    }

a chamadao no meu componente eu entendi será um e que ela deve extender uma classe chamada Dao…

manager.createDao(ConfiguracaoDao.class);
T dao = new Mirror().on(daoType).invoke().constructor().withArgs(session);

import de net.vidageek.mirror.dsl

não precisa ser necessariamente uma classe Dao, pode ser uma interface, e pode se chamar o que vc quiser

@boneazul

Poderia postar como ficou sua classe?
A solução adotada foi essa mesma?