为什么@Scheduled注释不适用于@Transaction批注.春季启动

Art*_*nov 9 java spring scheduled-tasks spring-transactions spring-boot

我有一个问题:为什么当我们使用@Scheduledand 注释方法时@Transaction,事务不起作用?我知道@Scheduled调用我的类而不是Spring创建的代理类,但无法理解这种行为.

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements UserService {

    @Override
    @Scheduled(fixedRateString = "${somestring}",initialDelayString = "${anotherstring}")
    @Transactional
    public void doSomething() {

        }
    }
Run Code Online (Sandbox Code Playgroud)

我有两个解决这个问题的方法:

  1. Scheduled方法调用代理.

  2. 用代理ConcurrentTaskScheduler 对象实现和替换ScheduledMethodRunnable(与我的类一起)的对象ScheduledMethodRunnable.

但是这种解决方案非常不方便.

你能解释一下为什么会@Scheduled这样吗?

谢谢!

tal*_*lex 5

发生这种情况是因为使用了 MAGIC 来处理这两个注释。

我想有几件事会发生:

  1. UserServiceImpl被建造。
  2. @Scheduled处理注释并存储对 bean 的引用以在适当的时间调用它。
  3. @Transactional注释已处理。它创建存储对原始 bean 的引用的代理。原始 bean 被替换为应用程序上下文中的代理。

如果步骤 2 和 3 以不同的顺序通过,那么就没有问题。

我不知道如何控制注释的处理顺序。我什至不确定这是否可能。

基本上有两种解决方案

  1. 使用不同种类的魔法来处理@Transaction。默认方式是创建代理对象,但可以指示Spring检测当前类。
  2. 将其拆分为两个类,每个类都具有仅带有一个注释的方法。

例子:

@Service
public class UserServiceImpl implements UserService {

    @Override
    @Transactional
    public void doSomething() {

    }
}

@Service
public class UserServiceScheduler {

    @Inject
    private UserService service;

    @Scheduled(fixedRateString = "${somestring}",initialDelayString = "${anotherstring}")
    public void doSomething() {
         service.doSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

我个人推荐第二种方法。