# Hibernate: Session is closed!



## Samson_Miller (24. Mrz 2009)

Hallo,

in meiner Anwendung wirft Hibernate nach einer noch unbestimmten Zeit eine Exception. Bei einem aktuellen Beispiel wird die Exception in einer DAO geworfen die eine SELECT-Abfrage an die Datenbank senden. Die DAO wird eine unbestimmte Anzahl erfolgreich durchlaufen. Nur auf einmal bekomme ich eine Exception das die Session geschlossen ist. Die Exception wird dann geworfen wenn versucht wird ein rollback durchzuführen. Es hilft dann nur noch den Tomcat neu zu starten.

Der Stacktrace: 

```
org.hibernate.SessionException: Session is closed!
	at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
	at org.hibernate.impl.SessionImpl.getTransaction(SessionImpl.java:1314)
	at sun.reflect.GeneratedMethodAccessor238.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
	at $Proxy11.getTransaction(Unknown Source)
	at com.xx.xyz.comp.dao.Dao.rollback(Dao.java:36)
	at com.xx.xyz.comp.dao.XyDao.get(XyDao.java:38)
	at com.xx.xyz.action.ActionAbc.execute(ActionAbc.java:52)
	at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
	at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
	at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
	at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:568)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
	at java.lang.Thread.run(Thread.java:595)
```

Die XyDao:


```
public List get(String arg0) {
		try {
			super.setSessionFactory(context);
			super.begin();
			List liste = super.getSession().createQuery("FROM Tabelle WHERE name=:name").setString("name",arg0).list();
			super.commit();
			super.close();
			return liste;
		} catch (HibernateException e) {
			super.rollback();
			throw e;
		}
	}
```

Warum wird diese DAO eine gewisse Zeit lang erfolgreich gelaufen und wirft dann doch eine Exception?


----------



## SlaterB (24. Mrz 2009)

warum weiß ich nicht, nur dass du noch weniger weißt, als du wissen könntest,
das rollback() wird doch anscheinend durch eine 'HibernateException e' ausgelöst, schau dir doch diese einmal an, vielleicht gibt sie wichtige Hinweise,

bei deinem jetztigen Aufbau geht sie ja anscheinend komplett unter?


----------



## byte (24. Mrz 2009)

Es fehlen jegliche Informationen, wie Deine SessionFactory konfiguriert ist und wie Du die Session erzeugst. Ich gehe mal davon aus, dass Du Hibernate 3.x benutzt.

Du solltest Deine Session nicht per SessionFactory#openSession() öffnen sondern per SessionFactory#getCurrentSession(). Wenn Du nicht irgendeine komische Konfiguration gewählt hast, liefert diese Methode die momentan an die Transaktion gebundene Session. Bei Bedarf wird eine neue Session aufgemacht, wenn die letzte bereits geschlossen ist.

Für Webanwendungen bietet es sich an, das Open-Session-In-View Pattern anzuwenden.


----------



## Samson_Miller (24. Mrz 2009)

Ja genau, ich benutzer Hibernate 3.

Die SessionFactory erstelle ich in einer anderen Dao, die in die XyDao eingebunden wird.


```
public class Dao {

	private static SessionFactory sessionFactory = null;
	
	protected Dao() {
	}

	public static Session getSession() {
		Session session = sessionFactory.getCurrentSession();
		if(session == null) {
			session = sessionFactory.openSession();
		}
		return session;
	}
	
	protected void begin() {
		getSession().beginTransaction();
	}

	protected void commit() {
		getSession().getTransaction().commit();
	}
   
	protected void rollback() {
		try {
			getSession().getTransaction().rollback();
		} catch( HibernateException e ) {
			log.info("Rollback nicht möglich",e);
			throw e;
		}
 
		try {
			getSession().close();
		} catch( HibernateException e ) {
			log.info("Schließen nicht möglich",e);
			throw e;
		}
	}
  
	public static void close() {
		getSession().close();
	}
	
	public static void setSessionFactory(ServletContext context) {
		sessionFactory=(SessionFactory)context.getAttribute("SessionFactory");
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}
```


----------



## SlaterB (24. Mrz 2009)

stell dir mal vor, zwei Daos benutzen die gleiche SessionFactory,
beide holen sich dieselbe Session (sessionFactory.getCurrentSession()), einer schließt zuerst, der zweite schaut in die Röhre

schau dir die Exception an (dürfe dann aber auch nur 'Session is closed' oder so sein),
lass dein Programm loggen, was der Teufel hergibt,
welche Daos sind aktiv, wer holt wann getSession(), welche Session (hashCode oder neu eingeführte Id), wer ruf wann begin(), commit(), close() usw auf,
die Ausgabe ist dann ein schönes Log:

...
X holt Session 3423;
X beginnt Transaktion für Session 3423;
X closed Session 3423;
Y holt Session 3424;
Y beginnt Transaktion für Session 3424;
Y closed Session 3424;
...

wenn dann irgendwo

A holt Session 4002;
A beginnt Transaktion für Session 4002;
B holt Session 4002;
A closed Session 4002;
B wirft Exception: Session 4002 ist closed, wieso nur? bin traurig

auftaucht, dann wäre die Sache klar 


------


kann aber auch an ganz was anderem liegen


----------



## Samson_Miller (24. Mrz 2009)

Was mich nur wundert ist, dass ich immer an der gleichen Stelle in der Anwendung den Fehler bekomme. Auch wenn ich mich abmelde und wieder neu anmelde und ich auch nur ganz alleine mit der Anwendung arbeite. Ich bekomme immer die Fehlermeldung "Session is closed", obwohl dann doch eine neue Session aufgemacht werden sollte.


----------



## byte (24. Mrz 2009)

SlaterB hat gesagt.:


> stell dir mal vor, zwei Daos benutzen die gleiche SessionFactory,
> beide holen sich dieselbe Session (sessionFactory.getCurrentSession()), einer schließt zuerst, der zweite schaut in die Röhre



Ne, Du kannst den Kontext der "Current Session" konfigurieren. Normaweilerweise ist die Current Session an den Thread gebunden (_ThreadLocalSessionContext_). In Webanwendungen läuft jeder Request in einem eigenen Thread im Webcontainer. Wenn nun zwei Requests parallel auf der selben SessionFactory getCurrentSession() aufrufen, bekommt jeder seine eigene (thread-local) Session.

Das ganze lässt sich über das Property *hibernate.current_session_context_class* konfigurieren.


@Samson_Miller: Guck doch mal nach, in welcher Zeile die Exception genau fliegt!!

Das session.close() würde ich übrigens rausnehmen, wenn Du die Session per getCurrentSession() holst. Die Session wird automatisch beim commit() geschlossen.


----------



## Samson_Miller (31. Mrz 2009)

Jetzt ist der Fehler wieder aufgetretten. Mit meiner Anwendung gehe ich gegen mehrere Datenbanken, die Fehlermeldung taucht aber immer nur bei einer Datenbank auf.

Wenn in der folgenden DAO:


```
public List get(String arg0) {
		try {
			super.setSessionFactory(context);
			super.begin();
			List liste = super.getSession().createQuery("FROM Tabelle WHERE name=:name").setString("name",arg0).list();
			super.commit();
			super.close();
			return liste;
		} catch (HibernateException e) {
			super.rollback();
			throw e;
		}
	}
```

die Funktion "super.getSession()" aufgerufen wird, wird folgendes Ausgeführt:


```
public static Session getSession() {
		Session session = sessionFactory.getCurrentSession();
               log.info("Die Session ist: "+session.isOpen());
		if(session == null) {
			session = sessionFactory.openSession();
		}
		return session;
	}
```

Wenn ich dort abfrage ob die Session geöffnet ist (session.isOpen()) wird in dem Fall "false" geliefert.


----------

