You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot下Hibernate懒加载异常:为何Job集合需手动初始化而Source不用

问题原因分析

这个异常的核心是你访问了已经关闭 Session 的懒加载集合代理,具体诱因有两个:

  • 第一:@PostConstruct 是 Spring Bean 初始化阶段的回调,此时事务切面尚未完成初始化,你方法上加的@Transactional注解根本不生效。每个Repository的save调用都会开启独立事务,执行完成后事务自动提交、Session 关闭。
  • 第二:Kotlin 默认所有类、方法、字段都是 final 的,Hibernate 要为实体生成动态代理实现懒加载,要求实体类是非 final 的。如果你的项目配置了kotlin-allopen插件,并且设置了自动为@Entity注解的类添加open修饰,就会出现两个实体表现不一致的情况:
    • Job 类被插件自动加了open修饰,Hibernate 可以成功生成代理,在调用jobRepository.save(initialJob)时,会把你构造函数中初始化的普通MutableSet替换为懒加载实现的PersistentSet代理。save 完成后 Session 关闭,后续调用targets.add时就会触发懒加载逻辑,抛出无 Session 异常。
    • Source 类因为某些原因没有被all-open插件处理,还是 final 类,Hibernate 无法生成代理,save 时不会替换你构造中初始化的普通集合,后续操作普通集合不需要访问数据库、不需要 Session,自然不会报错。

你手动加的initialJob.targets = mutableSetOf()本质是把 Hibernate 替换的懒加载代理集合覆盖为普通集合,绕开了懒加载逻辑,所以不会报错。

推荐解决方案
    1. 把初始化逻辑从@PostConstruct迁移到ApplicationReadyEvent事件监听中,此时 Spring 上下文完全初始化完成,@Transactional注解可以正常生效,整个初始化逻辑运行在同一个事务中,Session 不会提前关闭,懒加载集合可以正常操作:
@Component
class InitService(
    private val jobRepository: JobRepository,
    private val sourceRepository: SourceRepository,
    private val targetRepository: TargetRepository
) {
    @EventListener(ApplicationReadyEvent::class)
    @Transactional
    fun init() {
        // 原有初始化逻辑,不需要手动初始化集合
    }
}
    1. 调整关联操作逻辑:因为是双向关联,直接设置Target实体的source和job字段即可,不需要额外操作所属方的集合,关联关系会自动维护:
val target = Target()
target.source = source
target.job = initialJob
targetRepository.save(target)
    1. 确认kotlin-allopen插件的配置,保证所有@Entity类的代理策略一致,避免同类配置出现不同表现的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 12:27:03