Conexão Hibernate em tempo de execução

Pessoal,

Eu tenho uma aplicação web que usa Hibernate sem JPA, que faz login no banco server, mas, em tempo de execução as vezes preciso executar uma consulta no banco do cliente. Eu fiz alguma modificações na minha classe da fabrica de sessões do hibernate, mas, se estou em server e outra pessoa entra e consulta a base cliente altera a minha sessão no hibernate.

Segue a classe da fabrica de conexões:

public class ConexaoHibernate {
    
    
    	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
	private static SessionFactory sessionFactory = null;
	


	public static Session openSession(String servidor) {
            Configuration config = new AnnotationConfiguration().configure("hibernate.cfg.xml");
            config.setProperty("hibernate.connection.url",servidor);          
	    sessionFactory =  config.buildSessionFactory();
	    threadLocal.set(sessionFactory.openSession());
	    return threadLocal.get();	
        }
        	
    	public static void closeCurrentSession() {
    	    	sessionFactory.close();
    		threadLocal.get().close();
    		threadLocal.set(null);
    	}
    
    	public static Session getInstance() {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
            HttpSession sessionConfig = request.getSession();
            String url = (String) sessionConfig.getAttribute("configDeAcesso");
            
            if(sessionFactory == null || sessionFactory.isClosed()) {
                    openSession(url);
            }

            threadLocal.set(sessionFactory.openSession());
            return threadLocal.get();
    	}
}

Alguém consegui me dar uma dica ai?

[ ]'s a todos!

E se você enviar uma sessão para cada vez que um novo usuário requisitar um acesso aos dados? Você pode requisitar essa sessão nova e guardá-la nas suas classes de Business. Algo do tipo:

public class ConexaoHibernate {

    private static SessionFactory sessionFactory = null;

    // RETORNA UMA NOVA SESSÃO ABERTA PARA O SERVIDOR SELECIONADO.
    public static Session getSession(String servidor) throws HibernateException {

         Configuration configuration = new AnnotationConfiguration().configure("hibernate.cfg.xml");
         config.setProperty("hibernate.connection.url", servidor);
         
         sessionFactory = configuration.buildSessionFactory();
         return sessionFactory.openSession();
    }

Uma classe de Serviços pode ser definida da seguinte forma:

public class ServicosDisponiveis {

    private Session currentSession = null;
    /* RECEBO, NA HORA DA INSTÂNCIA DO OBJETO, A SESSÃO QUE ABRIREMOS. */
    public ServicosDisponiveis(Session currentSession) {
        this.currentSession = currentSession;
    }

    public String retornaUmValorQualquer() {

        /* FAZ QUALQUER OPERAÇÃO QUE BUSCA DADOS, USANDO 
            A SESSION QUE OBTIVEMOS NA INSTÂNCIA DA CLASSE. */
        return "Qualquer valor";
    }
}

E, nas classes de controle das suas páginas, pode existir algo do tipo:

/* CRIA UMA NOVA SESSÃO, DEPENDENDO DO NOME DO SERVIDOR QUE VOCÊ PASSA POR PARÂMETRO. */
Session currentSession = ConexaoHibernate.getSession("nome do seu servidor");

/* CRIA UMA INSTÂNCIA DA SUA CLASSE DE BUSINESS COM A SESSÃO QUE FOI ABERTA. */
ServicosDisponiveis servicosDisponiveis = new ServicosDisponiveis(currentSession);

/* REALIZA AS OPERAÇÕES NA BASE DE DADOS DEPENDENDO DAQUELA SESSÃO. */
String valorQualquer = servicosDisponiveis.retornaUmValorQualquer();

Seria algo assim que você está procurando?
Abraços!

Nicolas Fernandes,

Entendi o que você quis me passar na sua exemplificação. Mas a minha aplicação é padrão MVC, consigo aplicar isto também?

DTA

[ ]'s

[quote=BMuniz]Nicolas Fernandes,

Entendi o que você quis me passar na sua exemplificação. Mas a minha aplicação é padrão MVC, consigo aplicar isto também?

DTA

[ ]'s[/quote]

É exatamente isso que você deve fazer. Ali tá um “MVC bagunçado”, mas só pra você entender a ideia.
Sua aplicação é desktop ou WEB?

É uma aplicaçao Web.

Que tal se você fizer assim? Vou fazer um exemplo simples com alunos de várias faculdades. Você escolhe qual a faculdade na sua página e ele conecta a um determinado servidor de dados.

  1. Classe de domínio

[code]@Entity
@Table(name=“ALUNOS”, schema=“DBO”)
public class Aluno implements Serializable {
@Id
private Long ID;
@Column(name=“NOME”)
private String nome;

//getters e setters omitidos.

}[/code]

  1. Classe de persistência

[code]public class PersistenciaAluno {

private Session currentSession;
public PersistenciaAluno(Session currentSession) {
    this.currentSession = currentSession;
}

public Aluno recuperarUnico(Long ID) throws HibernateException {
    return (Aluno) currentSession.load(Aluno.class, ID);
}

}[/code]

  1. Classe de serviços

[code]public class ServicosAluno {

private Session currentSession;
public ServicosAluno(Session currentSession) {
    this.currentSession = currentSession;
}

public Aluno recuperarAlunoPorID(Long alunoID) throws HibernateException {

    PersistenciaAluno persistenciaAluno = new PersistenciaAluno(currentSession);
    return persistenciaAluno.recuperarUnico(alunoID);
}

}[/code]

Não sei se você tá trabalhando com JSP/Servlet ou com alguma framework mas, na classe de controle, você faz assim:
4. Classe de controle

String servidor = ""; /* suponhamos que você escolha o servidor na página e atribua a esta variável. */

Session currentSession = null;

currentSession = ConexaoHibernate.getSession("PUC" /* no caso, é nossa variável que vai como parâmetro */ );
ServicosAluno servicosAluno = new ServicosAluno(currentSession);
Aluno alunoDaPucComID100 = servicosAluno.recuperarAlunoPorID(100);
currentSession.close();

currentSession = ConexaoHibernate.getSession("USP" /* no caso, é nossa variável que vai como parâmetro */ );
ServicosAluno servicosAluno = new ServicosAluno(currentSession);
Aluno alunoDaUspComID100 = servicosAluno.recuperarAlunoPorID(100);
currentSession.close();

Sacou a ideia?

Entendi… agora mãos a obra.

Obrigadão!

[ ]'s e DTA!

Nicolas Fernandes,

Funciona, mas, eu vi que tem um lag em cada consulta, pois, ele fecha e abre novamente a session.

[ ]'s

DTA!

[quote=BMuniz]Nicolas Fernandes,

Funciona, mas, eu vi que tem um lag em cada consulta, pois, ele fecha e abre novamente a session.

[ ]'s

DTA![/quote]

É, era de se esperar isso. O que acontece é que, a cada vez que você requisita uma nova conexão, ele dá um build na SessionFactory (o lag tá aqui) e cria uma nova Session. E se fizer da seguinte maneira:

  1. O usuário da PUC começa a acessar o sistema. Você requisita uma conexão nova pra ele e guarda em uma sessão do browser para que ele faça uso de uma session só para ele;
  2. O usuário da EFEI começa a acessar o sistema. Você requisita uma conexão nova pra ele e guarda em uma sessão do browser para que ele faça uso de uma session só para ele.

ou, senão, você pode modelar a sua ConexaoHibernate de modo que seja um singleton e, a cada vez que mudar o servidor, aí sim ele dê um build na sessionFactory novamente! Algo do tipo:

[code]public class ConexaoHibernate {

private static ConexaoHibernate conexaoHibernate = new ConexaoHibernate();
public static ConexaoHibernate getInstance() { return conexaoHibernate; }
private ConexaoHibernate() {
    setServidorAtual("");
}

private String servidorAtual;
public String getServidorAtual() { return servidorAtual; }
private void setServidorAtual(String servidorAtual) { this.servidorAtual = servidorAtual; }

private SessionFactory sessionFactory;
private Session currentSession;

public Session getNewSession(String servidor) throws HibernateException {
    
    /* SE O SERVIDOR FOR DIFERENTE, AÍ SIM INSTANCIA UMA NOVA SESSIONFACTORY COM SEUS DADOS.*/
    if (!servidor.equals(servidorAtual)) {

        servidorAtual = servidor;
        Configuration configuration = new AnnotationConfiguration().configure("hibernate.cfg.xml");  
        configuration.setProperty("hibernate.connection.url", servidorAtual);  
       
        sessionFactory = configuration.buildSessionFactory();
    }
    
    if (currentSession == null) {
        currentSession = sessionFactory.openSession();
    }
    return currentSession;
}

}[/code]

Algo do tipo [fiz no olho, mas a ideia é por aí]. O que acha?
Abraços!

Eu vou tentar salvar a session do hibernate dentro da sessão do browser. Pois não posso ter o lag do singleton na aplicação.

Assim, que eu conseguir implementar te retorno, aqui.

Obrigadão

[]'s

[quote=BMuniz]Eu vou tentar salvar a session do hibernate dentro da sessão do browser. Pois não posso ter o lag do singleton na aplicação.

Assim, que eu conseguir implementar te retorno, aqui.

Obrigadão

[]'s[/quote]

Esse “lag” que é gerado será causado em ambas as situações. Coloca o breakpoint na sua aplicação na linha do ConexaoHibernate que tem o comando buildSessionFactory(). Você vai ver o tempo de resposta até ele criar essa sessão. Não importa se você salve a sessão no browser ou use o Singleton para gerar sessões, esse lag existirá toda vez que você precisar de uma sessão para um novo servidor. Portanto, veja qual das duas te agrada mais e mãos à obra!

Já implementei aqui e estou tendo um problema com o diskStore do EhCache.

net.sf.ehcache.CacheException: Cannot parseConfiguration CacheManager. Attempt to create a new instance of CacheManager using the diskStorePath

Sem o lag do BuildSessionFactory é impossível fazer, pelo menos eu não consegui.

[ ]'s