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

8 respostas
black_fire

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!

8 Respostas

ricardolecheta

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.

black_fire

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

“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.

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:

ricardolecheta

é 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:

Configuration cfg = new Configuration();
    Configuration cfg2 = new Configuration();

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

entao vc terá duas SessionFactory... :D

black_fire

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); }
	}       
}
ricardolecheta

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…

ricardolecheta

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

black_fire

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
...
	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); }
	}
...
Depois no getSession eu informo a session de qual banco de dados de que estou solicitando:
...
	/**
	 * 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;
	}
...
ricardolecheta

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…

Criado 3 de fevereiro de 2004
Ultima resposta 3 de fev. de 2004
Respostas 8
Participantes 2