我有以下案例:
- 开始交易
- 获取对象A
- 更新A
- 提交交易
- 与 A 一起执行一项长期任务
- 更新 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);
}
最佳答案
@Transactional
私有(private)方法在代理模式下不起作用:Does Spring @Transactional attribute work on a private method?这里唯一的公共(public)方法是 execute()
,因此您可以对它或整个类进行注释。
(顺便说一句,如果您将getJob()
和finishJob()
公开,@Transactional
仍然对它们不起作用,因为它们是通过execute()
从this
方法调用的,而不是通过事务管理生成的代理基础设施)。
您可以删除@Transactional
来自您的JobExecutionService
,移动getJob()
和finishJob()
(或者任何应该在独立事务中运行的方法)作为新服务的公共(public)方法,例如 TransactionalJobExecutionService
并将该新服务注释为 @Transactional
.
关于java - 在一个方法调用中在 JPA 中创建两个单独的事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43766798/