Hibernate - Erro na inicializacao e Dois Bancos (Tomcat 5)

E ai pessoal,

:?: Estou tendo um erro na inicialização do Hibernate, porém não sei se isso está interferindo no seu funcionamento, pois eu executei uma query e ela funcionou sem problemas.

2004-02-03 08:52:22,859 [INFO] util.NamingHelper - Creating subcontext: hibernate
2004-02-03 08:52:22,890 [WARN] impl.SessionFactoryObjectFactory - Could not bind factory to JNDI
javax.naming.NamingException: Context is read only
	at org.apache.naming.NamingContext.checkWritable(NamingContext.java:947)
	at org.apache.naming.NamingContext.createSubcontext(NamingContext.java:561)
...
	at java.lang.Thread.run(Thread.java:534)

:?: Alguém, por ai sabe como posso configurar dois bancos distintos no arquivo de configuração do Hibernate? Tentei fazer isso:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration
    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
    <session-factory name="java:comp/env/hibernate/SessionFactory">
        <property name="connection.datasource">java:comp/env/jdbc/ComputeasyPG</property>
        <property name="show_sql">true</property>
        <property name="dialect">net.sf.hibernate.dialect.PostgreSQLDialect</property>
        <property name="transaction.factory_class">net.sf.hibernate.transaction.JDBCTransactionFactory</property>
		<property name="jdbc.UserTransaction">java:comp/UserTransaction</property>

        <!-- Mapping files -->
        <mapping resource="br/com/computeasy/hibernate/exemplos/TmpUsuario.hbm.xml"/>
    </session-factory>

    <session-factory name="java:comp/env/hibernate/SessionFactory">
        <property name="connection.datasource">java:comp/env/jdbc/ComputeasyORCL</property>
        <property name="show_sql">true</property>
        <property name="dialect">net.sf.hibernate.dialect.OracleDialect</property>
        <property name="transaction.factory_class">net.sf.hibernate.transaction.JDBCTransactionFactory</property>
		<property name="jdbc.UserTransaction">java:comp/UserTransaction</property>

        <!-- Mapping files -->
        <mapping resource="br/com/computeasy/hibernate/exemplos/Usuario.hbm.xml"/>
    </session-factory>

</hibernate-configuration>

Valeu pessoal!
Um grande abraço para todos!

1 - se vc tirar este name do session-factory -> <session-factory name=“java:comp/env/hibernate/SessionFactory”> continua o erro?

2 - nunca fiz o Hibernate se conectar em dois bancos como vc está fazendo, mas para existem um método openSession(Connection connection) em SessionFactory que vc pode usar para o Hibernate usar a conexao que vc passou.

Isso mesmo, retirei o java:comp/env/hibernate/SessionFactory e o erro não ocorreu mais.
:?: Só uma coisa, para que serve este name?

[quote=“ricardolecheta”]
2 - nunca fiz o Hibernate se conectar em dois bancos como vc está fazendo, mas para existem um método openSession(Connection connection) em SessionFactory que vc pode usar para o Hibernate usar a conexao que vc passou.[/quote]

Vou precisar trabalhar constantemente com dois bancos de dados ou talvez até três… Estes acessos não serão esporádicos já que possuo sistemas distintos que trabalham com SQLServer, Oracle e Postgresql.
:idea: Se alguém por ai já teve alguma experiência semelhate. Qualquer dica vai ajudar muito…

Um abraço galera… :wink:

é para obter a SessionFactory a partir de um nome JNDI…

vc pode criar 2 Configuration… e para cada uma vc cria uma SessionFactory para obter suas Sessions…

o Configuration possui um método configure() que por default procura o hibernate.cfg.xml, mas vc pode passar outro assim:

[code]Configuration cfg = new Configuration();
Configuration cfg2 = new Configuration();

cfg.configure("/hibernate.cfg.xml");
cfg2.configure("/hibernate2.cfg.xml");
  
sessionFactory = cfg.buildSessionFactory();
sessionFactory2 = cfg2.buildSessionFactory(); [/code]

entao vc terá duas SessionFactory… :smiley:

Valeu acho que isso resolve o meu problema, deixo como hibernate.cfg.xml a conexão que eu mais uso e passo por parâmetros as outras.

  Estive lendo um tutorial sobre o Hibernate, e o autor utiliza um filter para resgatar a SessionFactory.
   :?: É realmente necessário utilizar um filter para gerenciar a SessionFactory?
  Por que a SessionFactory não pode ser chamada dentro do JavaBean. 
  Um abraço galera, segue abaixo o código utilizado no tutorial para resgatar a SessionFactory.  :wink: 

Retirado de: http://www.gloegl.de/5.html

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.cfg.Configuration;

public class SessionManager implements Filter
{
	protected static ThreadLocal hibernateHolder = new ThreadLocal(); 
	protected static ThreadLocal txHolder = new ThreadLocal(); 
	protected static SessionFactory factory;
	
	public void init(FilterConfig filterConfig) throws ServletException
	{
		// Initialize hibernate
		try
		{
			factory = new Configuration().configure().buildSessionFactory();
		}
		catch (HibernateException ex) { throw new ServletException(ex); }
	}
	
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
	throws IOException, ServletException
	{
		if (hibernateHolder.get() != null)
			throw new IllegalStateException(
					"A session is already associated with this thread!  "
					+ "Someone must have called getSession() outside of the context "
					+ "of a servlet request.");
		
		try {
			chain.doFilter(request, response);
		}
		finally {
			Session sess = (Session)hibernateHolder.get();
			Transaction tx = (Transaction)txHolder.get();
			if (sess != null) {
				hibernateHolder.set(null);
				
				try {
					if (tx != null) {
						tx.commit();
					}
					sess.close();
				}
				catch (HibernateException ex) { throw new ServletException(ex); }
			}
		}
	}
	
	public static Session getSession() throws HibernateException
	{
		Session sess = (Session)hibernateHolder.get();
		Transaction tx = (Transaction)txHolder.get();
		
		if (sess == null)
		{
			sess = factory.openSession();
			txHolder.set(sess.beginTransaction());
			hibernateHolder.set(sess);
		} else {
			if (tx == null) {
				throw new IllegalStateException("Transaction was allready rolled back");
			}
		}    
		return sess;
	}
	
	public static void rollback() throws HibernateException {
		Transaction tx = (Transaction)txHolder.get();
		if (tx == null) {
			throw new IllegalStateException("Transaction was allready rolled back");
		}
		
		tx.rollback();
		txHolder.set(null);
	}
	
	
	public void destroy() {
		try {
			factory.close();
		}
		catch (HibernateException ex) { throw new RuntimeException(ex); }
	}       
}

fazer isso é questão de gosto, a sacada é que vc deve ter uma SessionFactory apenas, neste exemplo o autor usou este Filter para controlar isso.

outro jeito seria simplesmente implementar o pattern ThreadLocal numa classe separada, assim:
http://www.hibernate.org/42.html
no exemplo foi feito o lookup para recuperar a SessionFactory… vc pode alterar isto se quiser, mas lembre-se de criar apenas uma nesta classe…

Ai é só usar esta classe HibernateSession.currentSession() para obter a Session de onde vc precisar…

a outra coisa, bacana este tutorial que vc passou :smiley:

Fiz uma alteração no filter.
Não tenho certeza se é uma alteração correta. ou se terei que fazer uma classe para cada um dos bancos de dados que estarei utilizando

Vejam:
Estarei pondo apenas partes do código acima:
Primeiro eu crio uma sessionFactory para cada banco de dados

[code]…
protected static SessionFactory factoryPG;
protected static SessionFactory factoryORCL;

public void init(FilterConfig filterConfig) throws ServletException	{
	// Initialize hibernate
	try
	{
		Configuration pg = new Configuration().configure("hibernate.cfg.xml");
		Configuration orcl = new Configuration().configure("Oracle.cfg.xml");
		
		factoryPG = pg.buildSessionFactory();
		factoryORCL = orcl.buildSessionFactory();
	}
	catch (HibernateException ex) { throw new ServletException(ex); }
}

…[/code]

Depois no getSession eu informo a session de qual banco de dados de que estou solicitando:

[code]…
/**
* Resgata a session atual:
*
* @param dataBase - 0: Postgresql, 1: Oracle
*/
public static Session getSession(int dataBase) throws HibernateException {
Session sess = (Session) hibernateHolder.get();
Transaction tx = (Transaction)txHolder.get();

	if (sess == null) {
		switch (dataBase) {
			case 0 : sess = factoryPG.openSession();
			case 1 : sess = factoryORCL.openSession();
		}
		txHolder.set(sess.beginTransaction());
		hibernateHolder.set(sess);
	} else {
		if (tx == null) {
			throw new IllegalStateException("Transaction was allready rolled back");
		}
	}    
	return sess;
}

…[/code]

o melhor é deixar um filtro apenas mesmo, me parece que sua alteração está certa sim.

O legal de fazer o filtro é que vc pode usar o pattern “Open Session in View”, isto é util quando vc usa o lazy-loading do Hibernate… pq se vc fechar a Session e mandar para a view, sempre que vc for acessar um objeto ainda nao carregado vai dar pau ! :slight_smile:

ai com o filter, a Session do Hibernate ainda vai estar aberta na view , entao vc pode usar o lazy-loading mais facil…