Hello,
I am using Hibernate 3.2 on WebSphere App Server 6.0 with JTA enabled, JNDI binding of the Hibernate Session, and WebSphere control of the datasource. I followed the Hibernate Reference manuals guidelines in section 11.2.2 for transaction demarcation and I use a Session.close() in the finally block of my DAOs to close the session and clean things up if there is an error. Why can I not call Session.close() in one EJB method call and then try to get the Session object again from JNDI in the same EJB method call?
My DAOs are called from Session EJBs, mostly stateless but a few state based. The problem occurs after I call one DAO from my EJB to get an object from the database, and then I call a second DAO to get another object or set of objects, the second DAO always throws a Hibernate exception stating that the session is closed. However, I can immediately call the same EJB method again, and it is able to open the session and get an object.
Below is my HibernateUtil code that all DAOs call to get a session object. I have also included my hibernate config file below.
Do I have to exit the EJB method and have my higher level application call another EJB method to start a new context and successfully get the Session object? There has to be another way.
Code:
package com.faweb.entities.utils;
import org.hibernate.*;
import org.hibernate.cfg.*;
import org.apache.log4j.*;
public class HibernateUtil {
static Logger logger = Logger.getLogger("com.faweb.entities.utils.HibernateUtil");
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
// get a logger instance named "com.foo"
sessionFactory = new Configuration().configure().buildSessionFactory();
if(logger.isEnabledFor(Level.INFO))
logger.info("Created Session Factory static class");
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
logger.error("Initial SessionFactory creation failed." + ex);
//System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
try {
logger.info("Looking up sessionFactory in JNDI in HibernateUtil.getSessionFactory()");
javax.naming.InitialContext ctx = new javax.naming.InitialContext();
logger.info("Got intiial JNDI context in HibernateUtil.getSessionFactory()");
SessionFactory sf = (SessionFactory) ctx.lookup("faweb/HibernateSessionFactory");
logger.info("Got SessionFactory in HibernateUtil.getSessionFactory()");
return sf;
}
catch (Exception e) {
logger.error("threw exception in HibernateUtil.getSessionFactory(). Exception is " + e);
return null;
}
}
}
Hibernate Config file:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.datasource">java:comp/env/fawebdbprod</property>
<property name="hibernate.dialect">org.hibernate.dialect.DB2Dialect</property>
<property name="hibernate.default_schema">faweb</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="jdbc.use_streams_for_binary">true</property>
<property name="hibernate.max_fetch_depth">3</property>
<property name="hibernate.default_batch_fetch_size">4</property>
<!-- Cache settings -->
<!-- <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> -->
<!-- Transaction API -->
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</property>
<!-- Isolation levels
/**
* A constant indicating that transactions are not supported.
*/
int TRANSACTION_NONE = 0;
/**
* A constant indicating that
* dirty reads, non-repeatable reads and phantom reads can occur.
* This level allows a row changed by one transaction to be read
* by another transaction before any changes in that row have been
* committed (a "dirty read"). If any of the changes are rolled back,
* the second transaction will have retrieved an invalid row.
*/
int TRANSACTION_READ_UNCOMMITTED = 1;
/**
* A constant indicating that
* dirty reads are prevented; non-repeatable reads and phantom
* reads can occur. This level only prohibits a transaction
* from reading a row with uncommitted changes in it.
*/
int TRANSACTION_READ_COMMITTED = 2;
/**
* A constant indicating that
* dirty reads and non-repeatable reads are prevented; phantom
* reads can occur. This level prohibits a transaction from
* reading a row with uncommitted changes in it, and it also
* prohibits the situation where one transaction reads a row,
* a second transaction alters the row, and the first transaction
* rereads the row, getting different values the second time
* (a "non-repeatable read").
*/
int TRANSACTION_REPEATABLE_READ = 4;
/**
* A constant indicating that
* dirty reads, non-repeatable reads and phantom reads are prevented.
* This level includes the prohibitions in
* <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the
* situation where one transaction reads all rows that satisfy
* a <code>WHERE</code> condition, a second transaction inserts a row that
* satisfies that <code>WHERE</code> condition, and the first transaction
* rereads for the same condition, retrieving the additional
* "phantom" row in the second read.
*/
int TRANSACTION_SERIALIZABLE = 8;
-->
<property name="hibernate.connection.isolation">2</property>
<property name="hibernate.connection.release_mode">auto</property>
<!-- <property name="transaction.manager_lookup_class">
net.sf.hibernate.transaction.WebSphereTransactionManagerLookup</property> -->
<!-- <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> -->
<property name="hibernate.jndi.url">iiop://localhost:2809/</property>
<property name="hibernate.jndi.class">com.ibm.websphere.naming.WsnInitialContextFactory</property>
<!-- <property name="hibernate.session_factory_name">java:comp/env/HibernateSessionFactory</property> -->
<property name="hibernate.session_factory_name">/faweb/HibernateSessionFactory</property>
<property name="hibernate.generate_statistics">true</property>
<property name="hibernate.jdbc.use_get_generated_keys">true</property>
<all my mapping resource declaratives appear here>
<!-- <property name="hibernate.hbm2ddl.auto" value="create"/>-->
</session-factory>
</hibernate-configuration>