Spring和线程:事务

为了能在我们的线程中使用事务,我们需要了解Spring中事务的工作机制。Spring中,事务信息存储在ThreadLocal变量中。因此,这些变量是某个线程上进行的事务所特有的(译注:这些变量对于其他线程中发生的事务来讲是不可见的,无关的)。

单线程的情况下,一个事务会在层级式调用的Spring组件之间传播。

但是在@Transactional注解的服务方法会产生一个新的线程的情况下,事务是不会从调用者线程传播到新建线程的。结果会是被调用者线程会说缺少事务(译注:这里指的应该是被调用者线程需要事务的情况,当然如果被调用者线程根本不需要事务,那它也不会说缺少事务的)。

如果被调用者线程发生的动作需要数据库访问比如通过JPA,那必须要创建一个事务。

通过查看注解@Transactional的文档我们可以获取更多关于事务传播类型的信息。@Transactional默认的传播模式是 REQUIRED

因此通过在使用异步注解@Async的方法上再加上注解@Transactional,这个在新线程中执行的异步任务上面,就会有一个新的事务被创建,而且它能够传播到在新线程中调用的其他服务方法上。

例子,我们的异步方法也可以再添加一个注解@Transactional来表明它需要事务:

// 一个异步方法,会使用一个新的事务,该事务跟该方法调用者是否使用事务,如何使用事务无关
@Async
@Transactional
public void executeTransactionally() {
    System.out.println("该逻辑在任务执行器线程中使用一个新的事务执行");
}

上面所讲的机制同样适用于使用Runnable实例时从其run()中调用异步方法的场景。异步注解@Async看起来简单易用,其实背后它还是被封装成了一个Runnable对象然后分发给了一个执行器对象。

总结一下,在Spring中使用异步线程和事务时,我们应该额外小心:需要谨记事务不会跨线程传播。最后,还要注意你使用@Async@Transactional注解的方法要是public的,这样才能确保它被调用时通过了对其执行一些必要动作的代理层(译注:比如代理会执行事务创建和提交等动作)

英文原文

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页