我想创建一个实体,并在事务中触发@Async
方法对同一实体执行某些更改。这些更改也应该保持异步。
问题:因为我必须在事务中触发异步方法,所以我可以使用实体中自动生成的@Id
。但是异步方法则必须首先通过该Id获取实体,并且通常这不存在。
只有当我在async方法中放置一些Thread.sleep()
作为第一个语句时,才能确保实体已被外部事务持久化。
但是那个解决方案并不是很好。问题:如何在异步方法中确保它应该等待实体存在于DB中?
@Service
public class OuterService {
@Service
private SyncService service;
@Transactional
public void process() {
service.mySyncMethod();
//etc
}
}
@Service
public class SyncService {
@Transactional
public void mySnycMethod() {
Entity entity = new MyEntity();
//fill entity
dao.save(entity);
asyncService.performLongRunningTask(entity.getId());
}
}
@Service
public class AsycnService {
@Async
@Transactional
public voi performLongRunningTask(Long id) {
//problem: is mostly == null because this is executed before the outer transaction completes
//only works if I put like Thread.sleep(5000) in between. but how can I really ensure the entity exists before executing this async lookup?
MyEntity entity = dao.findOne(id);
//perform long running task
//change some fields in entity accordingly
dao.save(entity);
}
}
答案 0 :(得分:1)
您可以使用TransactionSynchronizationManager.registerSynchronization()
在事务提交上注册一个挂钩并实现afterCommit()
方法。
@Transactional
public void mySnycMethod() {
Entity entity = new MyEntity();
// fill entity
dao.save(entity);
// performLongRunningTask will start after the transaction has been
// commited
TransactionSynchronizationManager
.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
asyncService.performLongRunningTask(entity.getId());
}
});
}
但请注意Javadocs在您的应用程序中使用TransactionSynchronizationManager
所说的内容:
由资源管理代码使用,但不是由典型应用程序使用 代码