I have a web-application which uses hibernate and for some reason every thread (httprequest or other threads related to queueing) uses a different session.
I've implemented a HibernateSessionFactory
class which looks like this:
public class HibernateSessionFactory {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new AnnotationConfiguration();
private static org.hibernate.SessionFactory sessionFactory;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {}
}
private HibernateSessionFactory() {}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();//This method basically does what the static init block does
}
session = (sessionFactory != null) ? sessionFactory.openSession(): null;
threadLocal.set(session);
}
return session;
}
//More non relevant methods here.
Now from my testing it seems that the threadLocal
member is indeed initialized only once when the class is first loaded by the JVM
but for some reason when different threads access the getSession()
method they use different sessions. When a thread first accesses this class (Session) threadLocal.get();
will return null but as expected all other access requests will yeild the same session. I'm not sure how this can be happening as the threadLocal
variable is final and the method threadLocal.set(session)
is only used in the above context (wh开发者_开发百科ich I'm 99.9% sure has to yeild a non null session as I would have encountered a NullPointerException
at a different part of my app).
I'm not sure this is relevant but these are the main parts of my hibernate.cfg.xml
file:
<hibernate-configuration>
<session-factory>
<property name="connection.url">someURL</property>
<property name="connection.driver_class"> com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.connection.isolation">1</property>
<property name="hibernate.connection.username">User</property>
<property name="hibernate.connection.password">Password</property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">false</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Mapping files -->
I'd appreciate any help granted and of course if anyone has any questions I'd be happy to clarify. Ittai
Are you aware of the purpose of ThreadLocal
?
From the docs:
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
You're getting a different Hibernate session for each thread precisely because that's what your code says to do.
Now, we can't really comment on whether this a good thing or not - although in many cases it's reasonably sensible. After all, you wouldn't want two threads to share the same session and interact with each other's transactions, would you?
精彩评论