You need to enable JavaScript to run this app. Spring Boot下Hibernate LAZY懒加载失效报no Session异常排查
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot下Hibernate LAZY懒加载失效报no Session异常排查

问题根因定位

你遇到的懒加载初始化异常,是三个配置/逻辑层面的问题叠加导致的:

  1. 事务管理器Bean名称错配,事务未真正生效

    Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.model.Fund.fundAlternateIds, could not initialize proxy - no Session
    你在数据库配置类中定义的事务管理器Bean的实际注册名称是sleeveTransactionManager,但在两个核心位置都引用了不存在的myTransactionManager:

    • @EnableJpaRepositories 配置项的transactionManagerRef = "myTransactionManager"
    • FundServiceImpl类上@Transactional("myTransactionManager")
      名称不匹配导致Spring无法找到对应的事务管理器,声明式事务切面完全失效。整个查询流程没有绑定Hibernate持久化Session,查询返回的Fund对象的关联集合都是未初始化的动态代理。
  2. 事务边界与JSON序列化阶段完全脱节
    就算修正了名称匹配问题,Spring声明式事务的默认边界仅覆盖Service方法内部逻辑。当Service方法把查询到的List<Fund>返回给控制层时,事务就会提交,绑定的Hibernate Session会被直接关闭。
    而你在Fund实体的fundAlternateIds字段上加了@JsonManagedReference注解,强制Jackson在序列化返回值时遍历读取这个字段。此时要初始化懒加载的代理集合,必须依托已经被关闭的Session,就会触发你看到的JsonMappingException序列化异常,对应栈中的引用链Collections$UnmodifiableRandomAccessList[0]->Fund["fundAlternateIds"]。
  3. 事务管理器的EntityManagerFactory绑定存在逻辑缺陷
    你当前的事务管理器实现里,手动调用getEntityManagerFactory(getDataSource()).getObject()构造实例,没有通过依赖注入的方式复用Spring容器托管的EntityManagerFactory,就算修正了名称匹配问题,也可能出现事务管理器和实际持久化逻辑使用的不是同一个Session工厂的问题,导致Session上下文完全不连通。
修正实现方案

第一步:修复基础配置错误(必须执行)

统一事务管理器的命名和绑定逻辑:

@Configuration
@EnableJpaRepositories(
        basePackages = {"com.example.repository"},
        entityManagerFactoryRef = "myEntityManagerFactory",
        // 保持和Bean注册名一致
        transactionManagerRef = "myTransactionManager"
)
@EnableTransactionManagement
public class ApplicationDatabaseConfiguration {

    // 其他原有Bean配置保持不变...

    // 把原来的sleeveTransactionManager Bean名改成myTransactionManager
    @Bean(name = "myTransactionManager")
    public PlatformTransactionManager transactionManager(
        // 直接通过依赖注入获取容器托管的EMF实例,不要手动构造
        @Qualifier("myEntityManagerFactory") LocalContainerEntityManagerFactoryBean emFactoryBean,
        @Qualifier("postGresDataSource") HikariDataSource dataSource
    ) {
        JpaTransactionManager tm = new JpaTransactionManager();
        tm.setEntityManagerFactory(emFactoryBean.getObject());
        tm.setDataSource(dataSource);
        return tm;
    }
}

第二步:根据业务需求匹配懒加载序列化策略

策略1:接口不需要返回关联的FundAlternateId数据(最匹配LAZY配置的设计目标)

  • 移除Fund实体中fundAlternateIds字段上的@JsonManagedReference注解
  • 直接给该字段加上@JsonIgnore注解,让序列化流程完全跳过该字段
  • 这种模式下序列化阶段不会访问懒加载代理,哪怕Session已关闭也不会触发异常,同时保留了事务范围内手动访问关联集合做业务校验的灵活性。

策略2:接口必须返回关联的FundAlternateId数据

  • 推荐实现:在事务范围内一次性加载关联数据
    直接在Repository层通过JOIN FETCH语法关联查询,避免序列化阶段触发懒加载:
    public interface FundRepository extends PagingAndSortingRepository<Fund, String> {
        // 新增带关联加载的查询方法
        @Query("SELECT f FROM fund f LEFT JOIN FETCH f.fundAlternateIds")
        List<Fund> findAllWithAlternateIds();
    }
    
    修改Service层的查询逻辑调用这个方法,整个加载过程都在事务范围内完成,返回的实体关联集合已经是初始化完成的普通数据对象,序列化阶段不需要再访问Hibernate Session。
  • 兜底实现:在Service方法返回前手动初始化懒加载集合
    @Override
    public List<Fund> getAllPublicFunds(Integer pageNo, Integer pageSize, String sortBy) {
        List<Fund> fundList = fundDao.getAllPublicFunds(pageNo, pageSize, sortBy);
        // 在事务生效范围内强制初始化懒加载集合
        fundList.forEach(fund -> Hibernate.initialize(fund.getFundAlternateIds()));
        return fundList;
    }
    
    注意这种方式在分页数据量大的时候会触发N+1查询问题,需要严格控制单次返回的Fund数量。
  • 快速但不推荐的方案:开启Open Session in View模式,把Hibernate Session的生命周期延伸到整个Web请求完成阶段。这种方式会长期占用数据库连接,容易引发连接池耗尽、慢查询等生产问题,不建议长期使用。

内容的提问来源于stack exchange,提问作者Pritam Bohra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 09:45:04