Получение нового сеанса из Hibernate для фонового потока

Я работаю над веб-приложением. Обычно в начале запроса (через код архитектуры) открывается сессия Hibernate для работы с транзакциями БД. По окончании запроса сессия закрывается. Это прекрасно работает для всех наших транзакций, за исключением одного конкретного случая, когда я хочу запустить поток из запроса. Этот поток будет вызывать транзакции БД.

Из потока я вызываю «sessionFactory.openSession()», и с помощью этого сеанса я выполняю свои транзакции. Проблема возникает в том, что когда запрос завершается, сам поток не обязательно может быть завершен. Поэтому, когда запрос завершается, и поток пытается выполнить другую транзакцию БД, я получаю, что сеанс Hibernate закрыт! ошибка.

В любом случае, из моего потока я могу открыть «чистый» сеанс, не связанный с сеансом, открытым в начале запроса?


person Jaime Garcia    schedule 25.02.2010    source источник
comment
Чтобы уточнить, вызывается ли openSession() из потока запроса или порожденного потока?   -  person skaffman    schedule 26.02.2010
comment
openSession сначала вызывается из запроса (сервлета), а затем снова из порожденного потока.   -  person Jaime Garcia    schedule 26.02.2010
comment
разве sessionFactory.openSession() не должен давать вам чистый сеанс, не связанный с сеансом, открытым в начале запроса? вы уверены, что ваш поток называется openSession, а не getCurrentSession?   -  person stmax    schedule 26.02.2010
comment
Это то, что я понял, и да, это вызывает openSession(). Если openSession() дает новый сеанс, то как получается, что сеанс порожденного потока умирает где-то посреди транзакций?   -  person Jaime Garcia    schedule 26.02.2010


Ответы (2)


Вы можете создать потоковую службу, которая расширяет HibernateAccessor, как автономную службу Spring, определенную в spring.xml, и отправлять в нее код/данные, которые вы хотите обработать. Что-то вроде этого:

    Session session = SessionFactoryUtils.getSession(
            getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
    SessionHolder sessionHolder = null;
    try {
        applyFlushMode(session, false);
        sessionHolder = new SessionHolder(session);
        TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
        Transaction t = getSessionFactory().getCurrentSession().beginTransaction();
        try {

            //execute your code here

            t.commit();
        } catch (Exception e) {
            t.rollback();
            log.error("Error", e);
        }
        try {
            flushIfNecessary(sessionHolder.getSession(), false);
        }
        catch (HibernateException ex) {
            throw convertHibernateAccessException(ex);
        }
    } finally {
        SessionFactoryUtils.closeSession(sessionHolder.getSession());
        TransactionSynchronizationManager.unbindResource(getSessionFactory());
    }
person Igor Artamonov    schedule 25.02.2010
comment
Будет ли это то, как я получу сеанс из порожденного потока? - person Jaime Garcia; 26.02.2010
comment
Да, этот пример создает сеанс, когда он выполняется в порожденном потоке. - person Igor Artamonov; 26.02.2010
comment
кстати, это будет новая сессия с новой транзакцией - person Igor Artamonov; 26.02.2010

Вы можете использовать JPA Entity Manager для запуска и фиксации транзакций вручную. Вот мой расширенный ответ

person adlerer    schedule 23.02.2018