HibernateException: Keine Hibernate-Sitzung an Thread in Hibernate 3 gebunden

Ausdauer oben

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Einleitung

In diesem kurzen Tutorial wird erläutert, wann die Ausnahme "Keine Sitzung im Ruhezustand an Thread gebunden" ausgelöst wird und wie sie behoben werden kann.

Wir werden uns hier auf zwei verschiedene Szenarien konzentrieren:

  1. Verwenden der LocalSessionFactoryBean
  2. Verwenden der AnnotationSessionFactoryBean

2. Die Ursache

Mit Version 3 führte Hibernate das Konzept der kontextbezogenen Sitzung ein und die Methode getCurrentSession () wurde der SessionFactory- Klasse hinzugefügt . Weitere Informationen zur kontextbezogenen Sitzung finden Sie hier.

Spring hat eine eigene Implementierung der Schnittstelle org.hibernate.context.CurrentSessionContext - org.springframework.orm.hibernate3.SpringSessionContext (im Fall von Spring Hibernate 3). Diese Implementierung erfordert, dass die Sitzung an eine Transaktion gebunden ist.

Natürlich sollten Klassen, die die Methode getCurrentSession () aufrufen, entweder auf Klassen- oder auf Methodenebene mit @Transactional versehen werden. Wenn nicht, wird die org.hibernate.HibernateException: Es wird keine an den Thread gebundene Hibernate-Sitzung ausgelöst.

Werfen wir einen kurzen Blick auf ein Beispiel.

3. LocalFactorySessionBean

Er ist das erste Szenario, das wir in diesem Artikel betrachten würden.

Wir werden eine Java Spring-Konfigurationsklasse mit LocalSessionFactoryBean definieren :

@Configuration @EnableTransactionManagement @PropertySource( { "classpath:persistence-h2.properties" } ) @ComponentScan( { "com.baeldung.persistence.dao", "com.baeldung.persistence.service" } ) public class PersistenceConfigHibernate3 { // ... @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); Resource config = new ClassPathResource("exceptionDemo.cfg.xml"); sessionFactory.setDataSource(dataSource()); sessionFactory.setConfigLocation(config); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; } // ... }

Beachten Sie, dass wir hier eine Hibernate-Konfigurationsdatei ( exceptionDemo.cfg.xml ) verwenden, um die Modellklasse zuzuordnen. Dies liegt daran , die org.springframework.orm.hibernate3.LocalSessionFactoryBean nicht die Eigenschaft bietet packagesToScan , für die Zuordnung von Modellklassen.

Hier ist unser einfacher Service:

@Service @Transactional public class EventService { @Autowired private IEventDao dao; public void create(Event entity) { dao.create(entity); } }
@Entity @Table(name = "EVENTS") public class Event implements Serializable { @Id @GeneratedValue private Long id; private String description; // ... }

Wie wir im folgenden Codeausschnitt sehen können, wird die Methode getCurrentSession () der SessionFactory- Klasse verwendet, um die Hibernate-Sitzung abzurufen :

public abstract class AbstractHibernateDao implements IOperations { private Class clazz; @Autowired private SessionFactory sessionFactory; // ... @Override public void create(T entity) { Preconditions.checkNotNull(entity); getCurrentSession().persist(entity); } protected Session getCurrentSession() { return sessionFactory.getCurrentSession(); } }

Der folgende Test besteht und zeigt, wie die Ausnahme ausgelöst wird, wenn die Klasse EventService, die die Dienstmethode enthält, nicht mit einer @ Transactional- Annotation versehen wird:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = { PersistenceConfigHibernate3.class }, loader = AnnotationConfigContextLoader.class ) public class HibernateExceptionScen1MainIntegrationTest { @Autowired EventService service; @Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void whenNoTransBoundToSession_thenException() { expectedEx.expectCause( IsInstanceOf.instanceOf(HibernateException.class)); expectedEx.expectMessage("No Hibernate Session bound to thread, " + "and configuration does not allow creation " + "of non-transactional one here"); service.create(new Event("from LocalSessionFactoryBean")); } }

Dieser Test zeigt, wie die Dienstmethode erfolgreich ausgeführt wird, wenn die EventService- Klasse mit der Annotation @Transactional versehen wird :

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = { PersistenceConfigHibernate3.class }, loader = AnnotationConfigContextLoader.class ) public class HibernateExceptionScen1MainIntegrationTest { @Autowired EventService service; @Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void whenEntityIsCreated_thenNoExceptions() { service.create(new Event("from LocalSessionFactoryBean")); List events = service.findAll(); } }

4. AnnotationSessionFactoryBean

Diese Ausnahme kann auch auftreten, wenn wir org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean verwenden , um die SessionFactory in unserer Spring-Anwendung zu erstellen .

Schauen wir uns einen Beispielcode an, der dies demonstriert. Insofern definieren wir mit AnnotationSessionFactoryBean eine Java Spring-Konfigurationsklasse :

@Configuration @EnableTransactionManagement @PropertySource( { "classpath:persistence-h2.properties" } ) @ComponentScan( { "com.baeldung.persistence.dao", "com.baeldung.persistence.service" } ) public class PersistenceConfig { //... @Bean public AnnotationSessionFactoryBean sessionFactory() { AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); sessionFactory.setPackagesToScan( new String[] { "com.baeldung.persistence.model" }); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; } // ... }

Bei denselben DAO-, Service- und Modellklassen aus dem vorherigen Abschnitt tritt die oben beschriebene Ausnahme auf:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class ) public class HibernateExceptionScen2MainIntegrationTest { @Autowired EventService service; @Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void whenNoTransBoundToSession_thenException() { expectedEx.expectCause( IsInstanceOf.instanceOf(HibernateException.class)); expectedEx.expectMessage("No Hibernate Session bound to thread, " + "and configuration does not allow creation " + "of non-transactional one here"); service.create(new Event("from AnnotationSessionFactoryBean")); } }

Wenn wir die Serviceklasse mit einer @ Transactional- Annotation versehen, funktioniert die Servicemethode wie erwartet und der unten gezeigte Test besteht:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class ) public class HibernateExceptionScen2MainIntegrationTest { @Autowired EventService service; @Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void whenEntityIsCreated_thenNoExceptions() { service.create(new Event("from AnnotationSessionFactoryBean")); List events = service.findAll(); } }

5. Die Lösung

Es ist klar, dass die von Spring erhaltene getCurrentSession () -Methode der SessionFactory innerhalb einer offenen Transaktion aufgerufen werden muss. Daher besteht die Lösung darin, sicherzustellen, dass unsere DAO / Service-Methoden / Klassen mit der Annotation @Transactional korrekt kommentiert werden .

Es ist zu beachten, dass in Hibernate 4 und späteren Versionen die Meldung der Ausnahme, die aus demselben Grund ausgelöst wird, anders formuliert ist. Anstelle der Option " Keine Sitzung im Ruhezustand an Thread gebunden" wird " Transaktionssynchronisierte Sitzung für aktuellen Thread konnte nicht abgerufen werden " angezeigt.

Es gibt noch einen weiteren wichtigen Punkt. Zusammen mit der org.hibernate.context.CurrentSessionContext Schnittstelle hat Hibernate eine Eigenschaft eingeführt hibernate.current_session_context_class die zur Klasse eingestellt werden kann implementiert , dass der aktuelle Session - Kontext.

Wie bereits erwähnt, verfügt Spring über eine eigene Implementierung dieser Schnittstelle: den SpringSessionContext. Standardmäßig setzt er die hibernate.current_session_context_class Eigenschaft dieser Klasse gleich.

Wenn wir diese Eigenschaft explizit auf etwas anderes setzen, wird die Fähigkeit von Spring, die Sitzung und die Transaktionen im Ruhezustand zu verwalten, beeinträchtigt. Dies führt ebenfalls zu einer Ausnahme, unterscheidet sich jedoch von der betrachteten Ausnahme.

Zusammenfassend ist es wichtig zu bedenken, dass wir die hibernate.current_session_context_class nicht explizit festlegen sollten, wenn wir Spring zum Verwalten der Hibernate-Sitzung verwenden.

6. Fazit

In diesem Artikel haben wir untersucht, warum in Hibernate 3 eine Ausnahme org.hibernate.HibernateException: Keine an Thread gebundene Hibernate-Sitzung zusammen mit einem Beispielcode ausgelöst wird und wie wir sie einfach lösen können.

Den Code für diesen Artikel finden Sie auf Github.

Persistenz unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs