Вот краткий ответ, который я нашел на этот вопрос здесь , если кто-то сталкивается с этой проблемой в Hibernate.Очевидно, это просто!
использование управляемых сеансов в спящем режиме для упрощения модульного тестирования 06nov06
Если вы когда-либо пытались повторно использовать сеанс в Hibernate, возможно, вы столкнулись с этим исключением…
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1319)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
at $Proxy0.beginTransaction(Unknown Source)
....
Причина этого в том, что Hibernate использует thread
управляемые сеансы.С этим типом управления сессиями Hibernate управляет сессией для вас.При первой попытке использовать сеанс Hibernate создаст его и прикрепит к локальному потоку.Когда вы фиксируете транзакцию в сеансе, Hibernate автоматически закрывает сеанс, что означает, что его нельзя использовать повторно.
Чтобы обойти эту проблему, лучше всего использовать managed
сеансы.Управляя сеансами, вы полностью контролируете создание, очистку, фиксацию и закрытие сеансов.Вот как.
В вашем hibernate.cfg.xml
измените свойство current_session_context_class
на managed
.
Чтобы создать session
и начать transaction
в этом session
, сделайте это…
org.hibernate.classic.Session session = HibernateUtil.getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
session.beginTransaction();
To commit
a transaction
в session
сделать это…
ManagedSessionContext.unbind(HibernateUtil.getSessionFactory());
session.flush();
session.getTransaction().commit();
session.close();
Чтобы использовать этот код в модульных тестах, я создал этот базовый класс тестирования модулей, которыйвсе мои юнит-тесты расширяются.Всякий раз, когда я хочу создать новый session
или transaction
, я вызываю метод createNewSessionAndTransaction()
.Для фиксации транзакции сеанса я вызываю метод commitTransaction()
.
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.ManagedSessionContext;
import util.HibernateUtil;
import junit.framework.TestCase;
/**
* Abstract unit test with helper methods for managed session control
*/
public abstract class ManagedSessionUnitTest extends TestCase {
/**
* Create a new Session.
*
* For this method to work, the application managed session strategy has to
* be enabled. This basically means that the life of a session is controlled
* by you and and not by Hibernate.
*
* To enable the application managed session strategy set the property
* hibernate.current_session_context_class to "managed".
*
* Within this method we create a new session and set the flush mode to
* MANUAL. This ensures that we have full control over when the session is
* flushed to the database.
*/
protected org.hibernate.Session createNewSession() {
org.hibernate.classic.Session session = HibernateUtil.getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
return (org.hibernate.Session) session;
}
/**
* Start a new Transaction in the given session
* @param session The session to create the transaction in
*/
protected void startNewTransaction(Session session) {
session.beginTransaction();
}
/**
* Shortcut method that creates a new session and begins a transaction in it
* @return A new session with a transaction started
*/
protected org.hibernate.Session createNewSessionAndTransaction() {
Session session = createNewSession();
startNewTransaction(session);
return session;
}
/**
* Commit the transaction within the given session. This method unbinds
* the session from the session context (ManagedSessionContext), flushes
* the session, commmits the session and then closes the session
* @param session The session with the transaction to commit
*/
protected void commitTransaction(Session session) {
ManagedSessionContext.unbind(HibernateUtil.getSessionFactory());
session.flush();
session.getTransaction().commit();
session.close();
}
}