Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring启动事务无法在计时器中工作_Java_Spring_Spring Boot - Fatal编程技术网

Java Spring启动事务无法在计时器中工作

Java Spring启动事务无法在计时器中工作,java,spring,spring-boot,Java,Spring,Spring Boot,我有一个如下的交易 @Transactional public void changeJobStatus(Long jobId){ JobEntity jobEntity = jobRepository.findOneForUpdate(jobId); ... } TimerTask task = new TimerTask() { @Override public void run() { changeJobSt

我有一个如下的交易

@Transactional
public void changeJobStatus(Long jobId){
    JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
    ...
}
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            changeJobStatus(jobId);
        }
    };
    timer.schedule(task, waitTime);
@Service
public class SimpleTransactionService {

    private final TransactionTemplate transactionTemplate;

    @Autowired
    public SimpleTransactionService(PlatformTransactionManager transactionManager){
        transactionTemplate = new TransactionTemplate(transactionManager);
    }

    public void executeTransaction(ITransactionService task){
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                task.transactionExecute();
            }
        });
    }
}
findOneForUpdate是用悲观锁查找数据库

public interface JobRepository extends CrudRepository<JobEntity, Long>{
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("select j from JobEntity j where j.id = :id")
    JobEntity findOneForUpdate(@Param("id") Long id);
}
会有一个例外:

javax.persistence.TransactionRequiredException: no transaction is in progress

为什么会发生这种情况?如果有办法在TimerTask中调用transaction?

changeJobStatus()
的调用有效地直接指向您的bean(自调用),因此在bean之间调用时不受通常的Spring代理的约束。因此,没有开始任何事务

请参阅:搜索“自我调用”

有几种可能的方法来实现这一点:

  • 您可以自动连接到您自己的bean的引用,这将通过代理来实现,并通过该代理进行调用
  • 您可以使用mode=“aspectj”,它执行字节码编织(增强)
  • 您可以通过PlatformTransactionManager手动控制交易
    我的方法将取决于这是孤立的还是常见的情况。如果常见,我会研究“aspectj”模式;但我可能希望它是一个异常值,我可以坚持使用标准的Spring“代理”模式。

    这是由Spring的AOP限制造成的。正如Thomas所建议的,手动控制事务可以解决这个问题,而不是使用@Transactional。下面是详细的实现

    我创建了一个简单的事务服务,如下所示

    @Transactional
    public void changeJobStatus(Long jobId){
        JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
        ...
    }
    
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                changeJobStatus(jobId);
            }
        };
        timer.schedule(task, waitTime);
    
    @Service
    public class SimpleTransactionService {
    
        private final TransactionTemplate transactionTemplate;
    
        @Autowired
        public SimpleTransactionService(PlatformTransactionManager transactionManager){
            transactionTemplate = new TransactionTemplate(transactionManager);
        }
    
        public void executeTransaction(ITransactionService task){
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                    task.transactionExecute();
                }
            });
        }
    }
    
    ITransactionService只是一个简单的接口,只有一种方法

    public interface ITransactionService {
        void transactionExecute();
    }
    
    下面是我在TimerTask中如何使用上面的内容

    public void addTimerTask(Object param, Long waitTime){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                simpleTransactionService.executeTransaction(() -> someOperation(param));
            }
        };
        timer.schedule(task, waitTime);
    }
    

    someOperation是实际执行的事务。使用simple transaction service和lambda,无需任何注释即可完成事务。

    尝试了此注释@EnableTransactionManagement(mode=AdviceMode.ASPECTJ),但仍然不起作用。手动控制事务有效,谢谢!我在下面发布了一个实现。