HibernateException: No Hibernate Session Bound to Thread in Hibernate 3

Uthållighetstopp

Jag tillkännagav just den nya Learn Spring- kursen, med fokus på grunderna i Spring 5 och Spring Boot 2:

>> KONTROLLERA KURSET

1. Introduktion

I den här korta handledningen kommer vi att klargöra när undantaget “Ingen viloläge session bunden till tråd” kastas och hur man löser det.

Vi fokuserar här på två olika scenarier:

  1. med LocalSessionFactoryBean
  2. med hjälp av AnnotationSessionFactoryBean

2. Orsaken

Med version 3 introducerade Hibernate konceptet för den kontextuella sessionen och metoden getCurrentSession () lades till SessionFactory- klassen. Mer information om den kontextuella sessionen finns här.

Spring har sin egen implementering av org.hibernate.context.CurrentSessionContext- gränssnittet - org.springframework.orm.hibernate3.SpringSessionContext (i fallet Spring Hibernate 3). Denna implementering kräver att sessionen är bunden till en transaktion.

Naturligtvis bör klasser som anropar getCurrentSession () -metoden antecknas med @Transactional antingen på klassnivå eller metodnivå . Om inte kommer org.hibernate.HibernateException: Ingen viloläge session bunden till tråd kastas.

Låt oss ta en snabb titt på ett exempel.

3. LocalFactorySessionBean

Han är det första scenariot som vi skulle titta på i den här artikeln.

Vi definierar en Java Spring-konfigurationsklass med LocalSessionFactoryBean :

@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; } // ... }

Observera att vi använder en Hibernate-konfigurationsfil ( exceptionDemo.cfg.xml ) här för att kartlägga modellklassen. Detta beror på att det org.springframework.orm.hibernate3.LocalSessionFactoryBean inte ger egenskapen packagesToScan , för att kartlägga modellklasser.

Här är vår enkla tjänst:

@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; // ... }

Som vi kan se i kodavsnittet nedan används metoden getCurrentSession () för SessionFactory- klassen för att få Hibernate-sessionen:

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(); } }

Testet nedan passerar och visar hur undantaget kommer att kastas när klassen EventService som innehåller servicemetoden inte kommenteras med en @Transactional- kommentar:

@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")); } }

Detta test visar hur servicemetoden körs framgångsrikt när klassen EventService antecknas med @Transactional- anteckningen:

@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

Detta undantag kan också inträffa när vi använder org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean för att skapa SessionFactory i vår vårapplikation .

Låt oss titta på någon exempelkod som visar detta. I denna utsträckning definierar vi en Java Spring-konfigurationsklass med AnnotationSessionFactoryBean :

@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; } // ... }

Med samma uppsättning DAO-, service- och modellklasser från föregående avsnitt stöter vi på undantaget som beskrivs ovan:

@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")); } }

Om vi ​​kommenterar serviceklassen med en @Transactional- kommentar, fungerar servicemetoden som förväntat och testet som visas nedan passerar:

@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. Lösningen

Det är tydligt att getCurrentSession () -metoden för SessionFactory erhållen från Spring måste anropas från en öppen transaktion. Därför är lösningen att se till att våra DAO / servicemetoder / klasser kommenteras korrekt med @Transactional- anteckningen.

Det bör noteras att i Hibernate 4 och senare versioner är meddelandet om undantaget som kastas av samma anledning annorlunda formulerat. I stället för " Ingen viloläge session bunden till tråd", skulle vi få " Kunde inte hämta transaktions-synkroniserad session för aktuell tråd".

Det finns en annan viktig punkt att göra. Tillsammans med gränssnittet org.hibernate.context.CurrentSessionContext har Hibernate introducerat en egenskap hibernate.current_session_context_class som kan ställas in till klassen som implementerar det aktuella sessionskontexten.

Som tidigare nämnts kommer Spring med sin egen implementering av detta gränssnitt: SpringSessionContext. Som standard sätts egenskapen hibernate.current_session_context_class lika med den här klassen.

Som en konsekvens, om vi uttryckligen ställer in den här egenskapen till något annat, stör det Springs förmåga att hantera viloläge och transaktioner. Detta resulterar också i ett undantag men skiljer sig från undantaget som övervägs.

Sammanfattningsvis är det viktigt att komma ihåg att vi inte bör ställa in hibernate.current_session_context_class uttryckligen när vi använder våren för att hantera Hibernate-sessionen.

6. Sammanfattning

I den här artikeln tittade vi på varför en när undantaget org.hibernate.HibernateException: No Hibernate Session Bound to Thread kastas i Hibernate 3 tillsammans med någon exempelkod och hur vi enkelt kan lösa det.

Koden för den här artikeln finns på Github.

Uthållighet botten

Jag tillkännagav just den nya Learn Spring- kursen, med fokus på grunderna i Spring 5 och Spring Boot 2:

>> KONTROLLERA KURSET