从另一个线程调用@Transactional 方法(Runnable) [英] Calling @Transactional methods from another thread (Runnable)

查看:52
本文介绍了从另一个线程调用@Transactional 方法(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆