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

标签 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);

}

最佳答案

@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/

相关文章:

java.io.FileNotFoundException 访问被拒绝

java - 无法使用 Saxon 处理器应用区间算术

java - 如何监听Firebase数据库集合的变化?

java - Spring为QueueChannel集成多线程

java - Spring:使用 POST 请求保存带有外键的对象

java - MIDI 输入的实时解析 - 节奏区分

spring - 在 Spring Boot 中理解 Redis

java反射superClass被hibernate加载的问题

java - 事务注释不起作用

java - Hibernate 命名查询 ClassCastException