Spring Boot中Hibernate与JPA混合使用引发的异常排查及解决
解决Spring Boot中Hibernate SessionFactory与JPA混用的两类异常
我来帮你一步步拆解这两个异常的原因和解决办法,都是Spring整合Hibernate/JPA时常见的坑:
第一个异常:java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate5.SessionHolder
问题根源
你同时配置了Hibernate的SessionFactory和JPA的EntityManagerFactory,但Spring的事务管理器在绑定线程上下文时,只能维护一种事务资源持有者。比如如果你的事务管理器用的是JpaTransactionManager,它会把EntityManagerHolder绑定到线程;但你的代码里又调用了SessionFactory.getCurrentSession(),这个方法期望线程绑定的是SessionHolder,自然就出现类型转换错误了。
解决办法
根据你的需求选一种方案:
- 方案1:统一使用JPA规范
抛弃自定义的SessionFactory配置,完全用EntityManager来操作,通过entityManager.unwrap(Session.class)获取Hibernate的Session(如果需要Hibernate特有API),这样事务管理器用JpaTransactionManager就能统一管理。 - 方案2:统一使用Hibernate的SessionFactory
如果坚持用SessionFactory,把事务管理器换成HibernateTransactionManager,确保所有事务操作都基于SessionFactory的Session,避免混合JPA的EntityManager操作。 - 方案3:适配两种事务资源(不推荐)
配置ChainedTransactionManager同时管理JpaTransactionManager和HibernateTransactionManager,但这种方式复杂度高,容易引发其他事务问题,除非你有必须同时用两者的强需求,否则不建议。
第二个异常:java.lang.IllegalStateException: No transactional EntityManager available
问题根源
你用@PersistenceContext注入的EntityManager是非事务型的,当你调用loadById这类需要在事务上下文执行的操作时(比如懒加载、实体状态修改),Spring没有为当前线程绑定一个事务型的EntityManager,所以抛出这个异常。
解决办法
- 给业务方法添加事务注解
在调用EntityManager的业务方法(比如loadById所在的Service方法)上添加@Transactional注解,Spring会自动开启事务,并把事务型的EntityManager绑定到当前线程。示例:@Service public class YourEntityService { @PersistenceContext private EntityManager entityManager; @Transactional(readOnly = true) // 查询用readOnly更高效 public YourEntity loadById(Long id) { Session session = entityManager.unwrap(Session.class); return session.get(YourEntity.class, id); } } - 检查Spring事务配置
确保Spring Boot的自动配置已经启用了事务管理(默认是启用的,但如果自定义了配置,要确保@EnableTransactionManagement注解已经添加到配置类上)。
另外提醒一句:Spring Boot中尽量避免同时混用SessionFactory和JPA的EntityManager,除非你非常清楚两者的事务上下文机制,否则很容易踩这类事务绑定的坑,统一用一种方式会更省心。
内容的提问来源于stack exchange,提问作者Rasool Ghafari
相关产品推荐
相关产品推荐

