从另一个线程调用@Transactional方法(可运行)

2022-09-02 03:09:07

有没有简单的解决方案可以在新线程中使用JPA将数据保存到数据库中?

我的基于Spring的Web应用程序允许用户管理计划的任务。在运行时,他可以创建和启动预定义任务的新实例。我正在使用Spring的TaskScheduler,一切正常。

但是我需要将每个触发任务的布尔结果保存到数据库中。我该怎么做?

编辑:我必须概括我的问题:我需要从任务中调用@Service类上的方法。因为任务结果在保存到数据库之前必须“处理”。

编辑2:我的问题代码的简化版本来到这里。当从调度程序调用 saveTaskResult() 时,将打印出消息,但不会将任何内容保存到 db 中。但是每当我从控制器调用 saveTaskResult() 时,记录就会正确保存到数据库中。

@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);
    }

}

答案 1

代码的问题在于,您希望在调用 时启动事务。这不会发生,因为Spring使用AOP来启动和停止交易。saveTaskResult()

如果你从豆工厂或通过依赖注入获得一个事务性Spring bean的实例,你得到的实际上是一个围绕bean的代理。此代理在调用实际方法之前启动事务,并在方法完成后提交或回滚事务。

在这种情况下,您调用 Bean 的本地方法,而无需通过事务代理。将方法(注释为 )放入另一个Spring bean中。将另一个Spring Bean注入DemoService,并从DemoService调用另一个Spring Bean,一切都会好起来的。saveTaskResult()@Transactional


答案 2

事务保存在线程本地存储中。
如果您的其他方法正在运行带有注释的线程。
默认值设置为,这意味着如果运行从其他线程使用进行注释的方法,则将有一个新事务(因为此线程的线程本地存储中没有保留事务)。@TransactionalREQUIRED@Transacitonal


推荐