Почему каждый поток в моем приложении использует свой сеанс гибернации? - PullRequest
3 голосов
/ 27 апреля 2010

У меня есть веб-приложение, которое использует hibernate, и по какой-то причине каждый поток (httprequest или другие потоки, связанные с очередями) использует другой сеанс. Я реализовал класс HibernateSessionFactory, который выглядит следующим образом:

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.

Теперь из моего тестирования кажется, что элемент threadLocal действительно инициализируется только один раз, когда класс загружается JVM, но по какой-то причине, когда разные потоки обращаются к методу getSession(), они используют разные сеансы. Когда поток впервые обращается к этому классу, (Session) threadLocal.get(); вернет ноль, но, как и ожидалось, все другие запросы на доступ приведут к тому же сеансу. Я не уверен, как это может происходить, поскольку переменная threadLocal является окончательной, а метод threadLocal.set(session) используется только в вышеприведенном контексте (который, я уверен, на 99,9% должен вызывать не нулевой сеанс, как я бы обнаружил NullPointerException в другой части моего приложения).

Я не уверен, что это актуально, но это основные части моего hibernate.cfg.xml файла:

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

Буду признателен за любую предоставленную помощь, и, конечно, если у кого-то возникнут вопросы, я с удовольствием проясню. Еффий

1 Ответ

7 голосов
/ 27 апреля 2010

Знаете ли вы о цели из ThreadLocal?

С Документы :

Этот класс предоставляет локальный поток переменные. Эти переменные отличаются от их нормальные аналоги в том, что каждый поток, который обращается к одному (через его получить или установить метод) имеет свой собственный, независимо инициализированная копия переменная. ThreadLocal экземпляры как правило, частные статические поля в классы, которые хотят связать государство с потоком (например, идентификатор пользователя или ID транзакции).

Вы получаете разные сессии Hibernate для каждого потока именно потому, что это говорит ваш код.

Теперь мы не можем прокомментировать, хорошо это или нет - хотя во многих случаях это достаточно разумно. В конце концов, вы бы не хотели, чтобы два потока совместно использовали один и тот же сеанс и взаимодействовали друг с другом, не так ли?

...