Spring Boot 中的 Hibernate 无法懒惰地初始化角色集合,无法初始化代理 - 没有 Session 异常

Posted

技术标签:

【中文标题】Spring Boot 中的 Hibernate 无法懒惰地初始化角色集合,无法初始化代理 - 没有 Session 异常【英文标题】:Hibernate in Spring Boot failed to lazily initialize a collection of role, could not initialize proxy - no Session exception 【发布时间】:2021-11-27 17:23:12 【问题描述】:

我有三个实体,其中两个每个都包含第三个的集合。当我通过使用第三个实例创建两个“拥有”实体来设置它们时,只有一个可以正常工作。另一个在添加时抛出此异常,即使集合的设置方式完全相同:

“拥有”实体:

@Entity
class Source(
    @OneToMany(mappedBy = "source", cascade = [CascadeType.ALL]) 
    var targets: MutableSet<Target> = mutableSetOf(),
    @Id @GeneratedValue 
    var id: Long? = null,
) 
    fun addTarget(target: Target) 
        targets.add(target)
        target.source = this
    


@Entity
class Job(
    @OneToMany(mappedBy = "job", cascade = [CascadeType.ALL]) 
    var targets: MutableSet<Target> = mutableSetOf(),
    @Id @GeneratedValue 
    var id: Long? = null,
) 
    fun addTarget(target: Target) 
        targets.add(target) // exception actually thrown here
        target.job = this
    

共同“拥有”的实体:

@Entity
class Target(
    @ManyToOne var source: Source? = null,
    @ManyToOne var job: Job? = null,
    @Id @GeneratedValue var id: Long? = null
)

设置如下:

@PostConstruct
@Transactional
fun init() 
    val initialJob = Job()
    initialJob.targets = mutableSetOf() // no idea why this is necessary, but without it I get the exception
    jobRepository.save(initialJob)
    
    val source = Source()
    sourceRepository.save(source)
    
    val target = Target()
    
    source.addTarget(target) // this works fine
    initialJob.addTarget(target) // but this doesn't unless I initialize the set above
    targetRepository.save(target)
    sourceRepository.save(source)
    jobRepository.save(initialJob)

我很困惑为什么我需要手动初始化 Job 实体上的集合,而不是 Source 实体上的集合,因为在我看来这些关系是完全相同的。另外,Job 实体已经在其构造函数中初始化集合。

【问题讨论】:

【参考方案1】:

我认为问题在于@PostConstruct@Transactional 的组合。

@PostConstructpostProcessBeforeInitialization 阶段之后被调用。在 postProcessAfterInitialization 阶段创建 @Transactional 代理时。

因此,该方法未包装在一个事务中,您会收到no session 异常。

您可以尝试使用@EventListener 方法。

@Component
class SomeListener 
  @Autowired
  private MyService service;

  @EventListener
  public void onInit(ContextRefreshedEvent e) 
    service.init();
  

【讨论】:

很有趣。实际上,我最终进行了重构以完全避免该问题,但这是一个非常有趣的想法。你也许是对的。我会看看我是否可以设置一个场景来测试它。谢谢! 很高兴能帮到你。请把我的帖子标记为答案好吗? 是的,做到了。我从服务的 init() 方法中删除了 @PostConstruct 注释,并从事件侦听器中显式调用它。谢谢!

以上是关于Spring Boot 中的 Hibernate 无法懒惰地初始化角色集合,无法初始化代理 - 没有 Session 异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot Hibernate 将数据插入 Postgres 中的错误列

无法从 Spring Boot REST 中的 Hibernate POJO 返回 JSON

Hibernate中的ManyToMany映射引用错误(由api生成的表名)表Spring Boot

动态数据源作为 Spring Boot + Hibernate 中的第二个数据源

Spring/Spring boot JSR-303验证框架 之 hibernate-validator

Spring/Spring boot JSR-303验证框架 之 hibernate-validator