Spring与Hibernate问题:无法获取当前线程的事务同步Session
嘿,我之前也踩过Spring Boot整合Hibernate JPA时获取Session失败的坑,结合你描述的情况,咱们一步步来排查和解决:
首先,最常见的问题:获取Session的方式不对
Spring Boot整合JPA时,默认是通过EntityManager来管理持久化上下文的,直接调用Hibernate原生的SessionFactory.getCurrentSession()很容易出问题。推荐通过EntityManager来获取Session:
import org.hibernate.Session; import javax.persistence.EntityManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class HibernateSessionUtil { @Autowired private EntityManager entityManager; public Session getCurrentSession() { // 从EntityManager中unwrap出Hibernate Session return entityManager.unwrap(Session.class); } }
其次,确保你的配置文件正确
在application.properties(或application.yml)里,必须配置好数据源和JPA相关参数,比如:
# 数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC spring.datasource.username=your_db_username spring.datasource.password=your_db_password # JPA/Hibernate配置 spring.jpa.hibernate.ddl-auto=update # 可选:create/create-drop/update/validate/none spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect # 根据你的数据库版本调整 spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
然后,必须在事务上下文里使用Session
Hibernate的CurrentSession是和事务绑定的,如果在非事务方法里调用,大概率会报错。所以要给调用Session的方法加上@Transactional注解:
import org.hibernate.Session; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class YourService { @Autowired private HibernateSessionUtil sessionUtil; @Transactional // 关键:开启事务 public void doDatabaseOperation() { Session session = sessionUtil.getCurrentSession(); // 这里执行你的CRUD操作,比如session.save(yourEntity); } }
如果坚持要用原生SessionFactory
如果你一定要直接使用Hibernate的SessionFactory,需要在配置类里正确创建并注入:
import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import javax.sql.DataSource; import java.util.Properties; @Configuration @EnableJpaRepositories(basePackages = "hello.repository") // 你的Repository包路径 public class HibernateConfig { @Autowired private DataSource dataSource; @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("hello.entity"); // 你的实体类包路径 JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(hibernateProperties()); return em; } @Bean public SessionFactory sessionFactory() { return entityManagerFactory().getObject().unwrap(SessionFactory.class); } private Properties hibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); properties.put("hibernate.show_sql", true); properties.put("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext"); return properties; } }
最后检查几个容易忽略的点:
- 实体类必须加上
@Entity注解,并且在packagesToScan指定的路径下 - 项目依赖里必须包含
spring-boot-starter-data-jpa和对应的数据库驱动(比如mysql-connector-java) - 不要手动new SessionFactory,一定要通过Spring容器注入,否则Spring无法管理Session的生命周期
内容的提问来源于stack exchange,提问作者Matej Martincevic
相关产品推荐
相关产品推荐

