从另一个线程调用@Transactional 方法(Runnable) [英] Calling @Transactional methods from another thread (Runnable)
问题描述
在新线程中使用 JPA 将数据保存到数据库中是否有任何简单的解决方案?
Is there any simple solution to save data into database using JPA in a new thread?
我的基于 Spring 的 Web 应用程序允许用户管理计划任务.在运行时,他可以创建和启动预定义任务的新实例.我正在使用 spring 的 TaskScheduler,一切正常.
My Spring based web application allows user to manage scheduled tasks. On runtime he can create and start new instances of predefined tasks. I am using spring's TaskScheduler and everything works well.
但我需要将每个已触发任务的布尔结果保存到数据库中.我该怎么做?
But I need to save boolean result of every fired task into database. How can I do this?
我必须概括我的问题:我需要从任务中调用 @Service 类上的方法.因为任务结果在存入数据库之前必须经过处理".
I have to generalize my question: I need to call a method on my @Service class from tasks. Because the task result has to be "processed" before saving into database.
编辑 2:我有问题的代码的简化版本出现在这里.从调度程序调用 saveTaskResult() 时,会打印出消息,但不会将任何内容保存到 db 中.但是每当我从控制器调用 saveTaskResult() 时,记录都会正确保存到数据库中.
EDIT 2: Simplified version of my problematic code comes here. When saveTaskResult() is called from scheduler, message is printed out but nothing is saved into db. But whenever I call saveTaskResult() from controller, record is correctly saved into database.
@Service
public class DemoService {
@Autowired
private TaskResultDao taskResultDao;
@Autowired
private TaskScheduler scheduler;
public void scheduleNewTask() {
scheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
// do some action here
saveTaskResult(new TaskResult("result"));
}
}, 1000L);
}
@Transactional
public void saveTaskResult(TaskResult result) {
System.out.println("saving task result");
taskResultDao.persist(result);
}
}
推荐答案
您的代码的问题是您希望在调用 saveTaskResult()
时启动事务.这不会发生,因为 Spring 使用 AOP 来启动和停止事务.
The problem with your code is that you expect a transaction to be started when you call saveTaskResult()
. This won't happen because Spring uses AOP to start and stop transactions.
如果你从 bean 工厂或者通过依赖注入获得一个事务性 Spring bean 的实例,你得到的实际上是一个围绕 bean 的代理.此代理在调用实际方法之前启动事务,并在方法完成后提交或回滚事务.
If you get an instance of a transactional Spring bean from the bean factory, or through dependency injection, what you get is in fact a proxy around the bean. This proxy starts a transaction before calling the actual method, and commits or rollbacks the transaction once the method has completed.
在这种情况下,您调用 bean 的本地方法,而无需通过事务代理.将 saveTaskResult()
方法(用 @Transactional
注释)放在另一个 Spring bean 中.将另一个 Spring bean 注入 DemoService,并从 DemoService 调用另一个 Spring bean,一切都会好的.
In this case, you call a local method of the bean, without going through the transactional proxy. Put the saveTaskResult()
method (annotated with @Transactional
) in another Spring bean. Inject this other Spring bean into DemoService, and call the other Spring bean from the DemoService, and everything will be fine.
这篇关于从另一个线程调用@Transactional 方法(Runnable)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!