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

Mat*_*iak 0 java spring hibernate jpa spring-transactions

我有以下案例:

  1. 开始交易
  2. 获取对象A
  3. 更新A
  4. 提交交易
  5. 与 A 一起执行一项长期任务
  6. 更新A(在事务中不是必需的,但它会很好)

如何做到这一点?我不想在步骤 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);

}
Run Code Online (Sandbox Code Playgroud)

Rom*_*kiy 5

@Transactional私有方法在代理模式下不起作用:Spring @Transactional 属性是否在私有方法上工作?这里唯一的公共方法是execute(),因此您可以对其进行注释,也可以对整个类进行注释。

(顺便说一句,如果您制作getJob()finishJob()公开,@Transactional仍然对它们不起作用,因为它们是从execute()方法调用的this,而不是通过事务管理基础设施生成的代理)。

您可以@TransactionalJobExecutionService、 movegetJob()finishJob()(或应在独立事务中运行的任何方法)作为公共方法删除到新服务,例如 ,TransactionalJobExecutionService并将该新服务注释为@Transactional