HibernateException: No Hibernate Session Bound to Thread in Hibernate 3

Persistentie top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Inleiding

In deze korte tutorial, we zullen verduidelijken wanneer de uitzondering "Geen slaapsessie gebonden aan thread" wordt gegenereerd en hoe deze kan worden opgelost.

We zullen ons hier concentreren op twee verschillende scenario's:

  1. de ... gebruiken LocalSessionFactoryBean
  2. de ... gebruiken AnnotationSessionFactoryBean

2. De oorzaak

Met versie 3 introduceerde Hibernate het concept van de contextuele sessie en de getCurrentSession () methode is toegevoegd aan de SessionFactory klasse. Meer informatie over de contextuele sessie vind je hier.

Spring heeft zijn eigen implementatie van de org.hibernate.context.CurrentSessionContext koppel - org.springframework.orm.hibernate3.SpringSessionContext (in het geval van Spring Hibernate 3). Deze implementatie vereist dat de sessie aan een transactie is gebonden.

Natuurlijk, klassen die bellen getCurrentSession () methode moet worden geannoteerd met @Transactional hetzij op klassenniveau of op methodeniveau. Zo niet, dan is het org.hibernate.HibernateException: geen slaapstandsessie gebonden aan thread zal worden gegooid.

Laten we snel een voorbeeld bekijken.

3. LocalFactorySessionBean

Hij is het eerste scenario waar we in dit artikel naar zouden kijken.

We zullen een Java Spring-configuratieklasse definiëren met LocalSessionFactoryBean:

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

Merk op dat we een Hibernate-configuratiebestand gebruiken (exceptionDemo.cfg.xml) hier om de modelklasse in kaart te brengen. Dit is zo omdat de org.springframework.orm.hibernate3.LocalSessionFactoryBean biedt de woning niet aan packagesToScan, voor het in kaart brengen van modelklassen.

Hier is onze eenvoudige service:

@Service @Transactional openbare klasse EventService {@Autowired privé IEventbao dao; public void create (Event entiteit) {dao.create (entiteit); }}
@Entity @Table (name = "EVENTS") openbare klasse Evenement implementeert Serializable {@Id @GeneratedValue privé Lange id; private String beschrijving; // ...}

Zoals we in het onderstaande codefragment kunnen zien, is de getCurrentSession () methode van de SessionFactory class wordt gebruikt om de Hibernate-sessie te verkrijgen:

openbare abstracte klasse AbstractHibernatenate implementeert IOperations {private Class clazz; @Autowired privé SessionFactory sessionFactory; // ... @Override public void create (T entity) {Preconditions.checkNotNull (entity); getCurrentSession (). persist (entiteit); } beschermde sessie getCurrentSession () {return sessionFactory.getCurrentSession (); }}

De onderstaande test slaagt en laat zien hoe de uitzondering wordt gegenereerd wanneer de class Evenementenservice die de servicemethode bevat, wordt niet geannoteerd met een @Transactional annotatie:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfigHibernate3.class}, loader = AnnotationConfigContextLoader.class) openbare klasse HibernateExceptionScen1MainIntegrationTest {@Autowired EventService-service; @Rule openbaar ExpectedException verwachtEx = ExpectedException.none (); @Test openbare leegte whenNoTransBoundToSession_thenException () {verwachteEx.expectCause (IsInstanceOf.instanceOf (HibernateException.class)); verwachteEx.expectMessage ("Geen slaapsessie gebonden aan thread," + "en configuratie staat het aanmaken" + "van niet-transactionele hier niet toe"); service.create (nieuwe gebeurtenis ("van LocalSessionFactoryBean")); }}

Deze test laat zien hoe de servicemethode met succes wordt uitgevoerd wanneer het Evenementenservice klasse is geannoteerd met de @Transactional annotatie:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfigHibernate3.class}, loader = AnnotationConfigContextLoader.class) openbare klasse HibernateExceptionScen1MainIntegrationTest {@Autowired EventService-service; @Rule openbaar ExpectedException verwachtEx = ExpectedException.none (); @Test openbare leegte whenEntityIsCreated_thenNoExceptions () {service.create (nieuwe gebeurtenis ("van LocalSessionFactoryBean")); Lijst met gebeurtenissen = service.findAll (); }}

4. AnnotationSessionFactoryBean

Deze uitzondering kan ook optreden wanneer we de org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean om het SessionFactory in onze Spring-applicatie.

Laten we eens kijken naar een voorbeeldcode die dit laat zien. In zoverre definiëren we een Java Spring-configuratieklasse met AnnotationSessionFactoryBean:

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

Met dezelfde set DAO-, Service- en Modelklassen uit de vorige sectie, komen we de uitzondering tegen zoals hierboven beschreven:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) openbare klasse HibernateExceptionScen2MainIntegrationTest {@Autowired EventService-service; @Rule openbaar ExpectedException verwachtEx = ExpectedException.none (); @Test openbare leegte whenNoTransBoundToSession_thenException () {verwachteEx.expectCause (IsInstanceOf.instanceOf (HibernateException.class)); verwachteEx.expectMessage ("Geen slaapsessie gebonden aan thread," + "en configuratie staat het aanmaken" + "van niet-transactionele hier niet toe"); service.create (nieuwe gebeurtenis ("van AnnotationSessionFactoryBean")); }}

Als we de serviceklasse annoteren met een @Transactional annotatie, de servicemethode werkt zoals verwacht en de onderstaande test slaagt:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {PersistenceConfig.class}, loader = AnnotationConfigContextLoader.class) openbare klasse HibernateExceptionScen2MainIntegrationTest {@Autowired EventService-service; @Rule openbaar ExpectedException verwachtEx = ExpectedException.none (); @Test openbare leegte whenEntityIsCreated_thenNoExceptions () {service.create (nieuwe gebeurtenis ("van AnnotationSessionFactoryBean")); Lijst met gebeurtenissen = service.findAll (); }}

5. De oplossing

Het is duidelijk dat de getCurrentSession () methode van de SessionFactory verkregen van Spring moet worden gebeld vanuit een open transactie. Daarom de oplossing is ervoor te zorgen dat onze DAO / Service-methoden / -klassen correct worden geannoteerd met de @Transactional annotatie.

Opgemerkt moet worden dat in Hibernate 4 en latere versies het bericht van de uitzondering die om dezelfde reden wordt gegenereerd, anders wordt geformuleerd. In plaats van de "Geen slaapsessie gebonden aan thread ”, we zouden krijgen "Kan geen transactie-gesynchroniseerde sessie ophalen voor huidige thread '.

Er is nog een belangrijk punt om te maken. Samen met de org.hibernate.context.CurrentSessionContext interface, heeft Hibernate een eigenschap geïntroduceerd slaapstand.current_session_context_class die kan worden ingesteld op de klasse die de huidige sessiecontext implementeert.

Zoals eerder vermeld, komt Spring met zijn eigen implementatie van deze interface: het SpringSessionContext. Standaard wordt de slaapstand.current_session_context_class eigenschap gelijk aan deze klasse.

Als we deze eigenschap daarom expliciet op iets anders instellen, verstoort dit het vermogen van Spring om de Hibernate-sessie en transacties te beheren. Dit resulteert ook in een uitzondering, maar wijkt af van de betreffende uitzondering.

Samenvattend is het belangrijk om te onthouden dat we de slaapstand.current_session_context_class expliciet wanneer we Spring gebruiken om de Hibernate-sessie te beheren.

6. Conclusie

In dit artikel hebben we gekeken naar waarom en wanneer de uitzondering org.hibernate.HibernateException: geen slaapstandsessie gebonden aan thread wordt in Hibernate 3 gegooid samen met een voorbeeldcode en hoe we het gemakkelijk kunnen oplossen.

De code voor dit artikel is te vinden op Github.

Persistentie onderaan

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS