在一次方法调用中在JPA中创建两个单独的事务

时间:2017-05-03 17:45:45

标签: java spring hibernate jpa spring-transactions

我有以下情况:

  1. 开始交易
  2. 获取对象A
  3. 更新A
  4. 提交交易
  5. 使用A
  6. 执行长任务
  7. 更新A(在交易中不需要,但会很好)
  8. 如何实现这一目标?我不想在步骤5中使用锁定表。步骤1-4的行为应该类似于“SELECT FOR UPDATE”。以下是我目前的代码。我正在执行的方法是 execute()。我正在测试它是通过从不同的应用程序实例执行它而我正在检查,如果实例A能够在表上执行操作而实例B正在执行 executeJob(job)

    @Service
    @Slf4j
    @Transactional
    public class JobExecutionService {
    
        private final Environment environment;
        private final TestJobRepository testJobRepository;
        private final TestJobResultRepository testJobResultRepository;
    
        @Autowired
        public JobExecutionService(Environment environment, TestJobRepository testJobRepository, TestJobResultRepository testJobResultRepository) {
            this.environment = environment;
            this.testJobRepository = testJobRepository;
            this.testJobResultRepository = testJobResultRepository;
        }
    
        public void execute() {
            TestJob job = getJob();
            executeJob(job);
            finishJob(job);
        }
    
        @Transactional
        public TestJob getJob() {
            TestJob testJob = testJobRepository.findFirstByStatusOrderByIdAsc(
                    0
            );
            testJob.setStatus(1);
            testJobRepository.save(testJob);
            return testJob;
        }
    
        public void executeJob(TestJob testJob) {
            log.debug("Execution-0: {}", testJob.toString());
            Random random = new Random();
            try {
                Thread.sleep(random.nextInt(3000) + 1000);
            } catch (InterruptedException e) {
                log.error("Error", e);
            }
            log.debug("Execution-1: {}", testJob.toString());
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void finishJob(TestJob testJob) {
            testJobResultRepository.save(
                    new TestJobResult(
                            null,
                            testJob.getId(),
                            environment.getProperty("local.server.port")
                    )
            );
        }
    
    }
    
    public interface TestJobRepository extends PagingAndSortingRepository<TestJob, Long>, QueryDslPredicateExecutor<TestJob> {
    
        @Lock(LockModeType.PESSIMISTIC_WRITE)
        TestJob findFirstByStatusOrderByIdAsc(Integer status);
    
    }
    

1 个答案:

答案 0 :(得分:4)

私有方法的

@Transactional在代理模式下不起作用:Does Spring @Transactional attribute work on a private method?这里唯一的一个公共方法是execute(),所以你可以注释它或整个类

(顺便说一下,如果您公开getJob()finishJob()@Transactional仍然无效,因为execute()方法通过{{1}调用它们而不是通过事务管理基础结构生成的代理。)

您可以从this中删除@Transactional,移动JobExecutionServicegetJob()(或在独立交易中应运行的任何方法)作为新服务的公共方法,例如{ {1}}并将新服务注释为finishJob()