spring jpa关于线程池异步执行导致detached entity passed to persist问题排查和解决

我这边有个批量插入用户OpenUser和应用OpenApp关联关系数据的操作,由于耗时较长时间,所以准备用线程池异步执行操作,然而却遇到了一个jpa的detached entity passed to persist问题,我这边的操作是批量保存一个OpenAppUser关联关系表,所以需要先获得对应OpenUser和OpenApp的引用,再设置到关联对象OpenAppUser里,然后在保存,我这边是先通过userRepository.findById(userId)获取到OpenUser,然后openAppUser.setOpenUser(openUser),在执行appUserRepository.save(openAppUser);时发生了如标题上的错误,说是OpenUser对象处于游离态,无法保存。

经过排查,我这边是因为OpenAppUser类里设置了@ManyToOne(cascade = CascadeType.ALL)级联OpenUser,所以在保存OpenAppUser的时候会级联操作OpenUser,本来在没有开线程异步的情况下,因为OpenUser之前通过findById查出来了,所以在jpa的PersistenceContext里是有该OpenUser的脱管对象的,这时候就不会报错,而在线程异步的情况下context里确没有该脱管对象了
(这里说明一下,为啥不开线程有,开了线程没有?)因为spring-boot默认jpa.open-in-view=true,会使用ThreadLocal在当前线程里保存EntityManager上下文信息,所以在整个controller里都是使用的同一个context

PersistenceContext持久性上下文有两种类型:

  • 事务范围的持久性上下文;当我们在事务中执行任何操作时,EntityManager 会检查持久性上下文。 如果存在,则将使用它。否则,它将创建一个持久性上下文
  • 扩展范围的持久性上下文;扩展持久性上下文可以跨越多个事务。我们可以在没有事务的情况下持久化实体,但不能在没有事务的情况下刷新它。

在@PersistenceContext注解里type可以指定范围:PersistenceContextType.TRANSACTION;PersistenceContextType.EXTENDED

而当我们用线程池异步的时候,拿不到之前的EntityManager的配置信息,而spring jpa repository默认的方法上都会自带一个事务,所以在执行完userRepository.findById(userId)获取到OpenUser之后,会commit,而commit操作会clear掉EntityManager里保存的脱管对象OpenUser,等到appUserRepository.save(openAppUser);保存的时候,由于引用的OpenUser已经没有在PersistenceContext上下文里了,不是脱管对象了(具体可以看EntityState entityState = getEntityState( entity, entityName, entityEntry, source );里面的实现,有几种判断条件,是不是脱管对象,有没有id、version等等属性),就会报detached entity passed to persist这个异常

所以根据实际情况,我们只要参考open-in-view=true产生对应的OpenEntityManagerInViewInterceptor拦截器改造一下自己线程里的PersistenceContext上下文生效范围,就可以解决该异常了

java开发码农

3 声望
0 粉丝
0 条评论
推荐阅读
由于锁超时让我发现了parallelStream并行流的关于线程上下文的一个坑
就我之前因为在处理jpa持久化对象上下文(文:[链接])时,parallelStream并行流给我的印象就是会读不到父线程的上下文的,所以应该在父线程里的事务和在parallelStream里的事务应该是区分的,而不是共用同一个事...

我不是码农阅读 287

Java8的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft32阅读 27.5k评论 1

一文彻底搞懂加密、数字签名和数字证书!
微信搜索🔍「编程指北」,关注这个写干货的程序员,回复「资源」,即可获取后台开发学习路线和书籍来源:个人CS学习网站:[链接]前言这本是 2020 年一个平平无奇的周末,小北在家里刷着 B 站,看着喜欢的 up 主视...

编程指北71阅读 33.6k评论 20

Java11的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft28阅读 19.3k评论 3

Java5的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft13阅读 21.8k

Java9的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft20阅读 15.3k

Java13的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft17阅读 11.2k

java开发码农

3 声望
0 粉丝
宣传栏