Java 当我添加@Async时,entityManager.flush()将引发异常
我使用的是Spring框架 我的项目结构是控制器➡️ 服务➡️ 逻辑 我在逻辑类中添加了Java 当我添加@Async时,entityManager.flush()将引发异常,java,spring,hibernate,transactions,Java,Spring,Hibernate,Transactions,我使用的是Spring框架 我的项目结构是控制器➡️ 服务➡️ 逻辑 我在逻辑类中添加了@Transactional。我正在使用EntityManager执行数据库操作。在每次数据库操作(选择、更新…)之后,我调用entityManager.flush()方法。 一切都很好 但为了提高性能,我在服务类中添加了@Async。 然后,当我调用entityManager.flush()时,会引发一个异常 我调试了源代码,发现EntityManager是通过使用ThreadLocal绑定到线程的,但是当
@Transactional
。我正在使用EntityManager执行数据库操作。在每次数据库操作(选择、更新…)之后,我调用entityManager.flush()
方法。
一切都很好
但为了提高性能,我在服务类中添加了@Async
。
然后,当我调用entityManager.flush()
时,会引发一个异常
我调试了源代码,发现EntityManager是通过使用ThreadLocal绑定到线程的,但是当我添加@Async时,会有一个新线程,这个新线程会创建一个新的EntityManager,这没问题。但是当我调用entityManager.flush()时,它将检查事务并调用JdbcResourceLocalTransactionCoordinatorImpl.isJoin()
方法,physicalTransactionDelegate
为空,因此将引发异常
physicalTransactionDelegate
在主线程中初始化。
如果要执行entityManager.flush(),应该怎么做?还是我对源头的理解有误
Controller.java
@GetMapping(value = "/getTest", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseDto execute(@Valid final RequestDto requestDto) {
List<CompletableFuture<Dto>> completableFutures = new ArrayList<>();
for (ItemRequestDto item : requestDto.getItemRequestDtoList()) {
completableFutures.add(service.execute(item));
}
}
我在github中创建了一个问题。
我找到了解决办法。
只需添加entityManager.joinTransaction()
我认为这是一个错误
- 没有@Async
- 当请求到来时,
将被调用,新的EntityManager将绑定到当前线程TransactionSynchronizationManager.bindResource((对象键,对象值)
- 然后,调用
以获取绑定的EntityManager。在此方法内,它将调用EntityManagerFactoryUtils.doGetTransactionalEntityManager(EntityManagerFactory emf,@Nullable Map properties,boolean synchronizedWithTransaction)
。此方法将调用EntityManager.joinTransaction()
来初始化JdbcResourceLocalTransactionCoordinatorImpl.getTransactionDriverControl()
TransactionDriverControlImpl physicalTransactionDelegate
- 当我们调用
时,将调用jdbResourceLocalTransactionCoordinatorImpl.isjoin()进行检查EntityManager.flush()
- 当请求到来时,
- 使用@Async
- 当请求到来时,
将被调用,新的EntityManager将绑定到当前线程TransactionSynchronizationManager.bindResource((对象键,对象值)
- 如果存在@Async,将创建一个新线程
- 然后,
被调用以获取绑定的EntityManager。但是在这个新线程中,没有绑定的EntityManager,因此将创建一个新的EntityManager,但是EntityManagerFactoryUtils.doGetTransactionalEntityManager(EntityManagerFactory emf,@Nullable Map properties,boolean Synchronized with Transaction)
将不会被调用。因此将不会初始化EntityManager.joinTransaction()
。TransactionDriverControlImpl physicalTransactionDelegate
- 调用
时。由于EntityManager.flush()
为空,将引发异常。TransactionDriverControlImpl physicalTransactionDelegate
- 当请求到来时,
EntityManager.jointTransaction()
@GetMapping(value = "/getTest", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseDto execute(@Valid final RequestDto requestDto) {
List<CompletableFuture<Dto>> completableFutures = new ArrayList<>();
for (ItemRequestDto item : requestDto.getItemRequestDtoList()) {
completableFutures.add(service.execute(item));
}
}
@Async("taskExecutor")
public CompletableFuture<InventoryInfoListDto> execute(final ItemRequestDto item) {
return CompletableFuture.completedFuture(logic.execute(item));
}
@Transactional(rollbackFor = Throwable.class, timeout = 60)
public ResponseDto execute(final ItemRequestDto item) {
// process...
}