我在Spring网络@transactional
中使用@Controller
方法调用@async
方法。 @transactional
方法将实体持久保存到Spring-wired javax.persistence.entitymanager
并调用@async
函数将某些衍生数据保存到分析服务器。 @async
函数取决于NativeQuery
来自其@PersistenceContext
的结果。
问题是@async
函数内的本机查询在第一个事务刷新之前正在运行,这意味着该实体尚未刷新到数据库。
在完成当前打开的交易后,确保 这是我的代码的简化版本(编辑 - 添加了一些额外的细节): WebController AsyncService 此外:如果我在持久性配置中打开 最后,如果我将 从我的应用程序中的多个不同的Web端点调用asyncMethod。 有没有办法(可能通过AOP?)告诉异步函数只在当前事务刷新后运行?@async
功能仅运行的最佳方法是什么?我尝试将@async
函数包装在其自己的@transactional(propagation = Propagation.REQUIRES_NEW)
注释中,并在调用异步方法之前在第一个事务中手动调用em.flush()
,但都没有改变结果。 / p>
@Controller
class WebController {
@PersistenceContext
EntityManager em;
@Autowired
AsyncService service;
@RequestMapping("/createObject")
@Transactional
@ResponseBody
public Obj createObj(Obj obj){
em.persist(obj);
//Run the time consuming async task for the newly-persisted entity
service.runAsyncMethod(obj.getId());
return obj;
}
}
@Service
@EnableAsync
class AsyncService {
@PersistenceContext
EntityManager em;
@Async
public void runMethod(Long itemId) {
//Run native query
Query query = em.createNativeQuery("select name from obj where id = :objId")
query.setParameter("objId", itemId);
List results = query.getResultsList()
//`results` is empty
}
}
hibernate.show_sql
,则打印的SQL语句看起来像,就像它们的顺序正确一样: Hibernate: insert into content (id, name) values (?, ?)
Hibernate: select name from obj where id = ?
service.runAsyncMethod()
电话打包在java.util.TimerTask
并安排延迟1秒,那么 会按预期工作。
答案 0 :(得分:1)
如果在事务提交(flush complete)之后调用异步方法,我们可以实现这一点。这可以通过在TransactionSynchronizationAdapter(Spring提供的抽象类)的overCommit()中调用async方法并在TransactionSynchronizationManager中注册此TransactionSynchronizationAdapter对象(这有助于事务同步)来实现。
前:
@Controller
class WebController {
@PersistenceContext
EntityManager em;
@Autowired
AsyncService service;
@Transactional
public Obj createObj(Obj obj){
em.persist(obj);
// Call the Async method only after transaction commit.
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
// Override the afterCommit which need to be executed after transaction commit
public void afterCommit() {
//Run the time consuming async task for the newly-persisted entity
service.runAsyncMethod(obj.getId());
}
}
return obj;
}
}