【问题标题】:Create two separate transactions in JPA within one method call在一个方法调用中在 JPA 中创建两个单独的事务
【发布时间】:2017-05-03 17:45:45
【问题描述】:

我有以下情况:

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

}

【问题讨论】:

  • 经过您的编辑,现在executeJob(job);finishJob(job); 是不同的交易,那么您现在有什么问题?
  • 为什么要用“@Transactional”注释类和单个方法。在类中添加“@Transactional”意味着它适用于每个方法。
  • 在班级级别,您需要有@EnableTransactionManagement 注释。
  • 我在这篇文章中添加了一些信息。 @UeliHofstetter 没有@Transaction 在类上我有“javax.persistence.TransactionRequiredException:没有事务正在进行中”。 @hagrawal 我的主班有@EnableTransactionManagement,所以我认为我不需要在单独的班级中使用它。 @hagrawal 我认为它应该以我想要的方式运行,但是在我测试它时,似乎不是。
  • 用@Transactional 注释私有方法没有意义。 stackoverflow.com/questions/4396284/…(至少,在代理模式下)。您在此处拥有的唯一一个公共方法是 execute(),因此您可以对其进行注释,也可以对整个类进行注释。

标签: java spring hibernate jpa spring-transactions


【解决方案1】:

私有方法上的@Transactional 在代理模式下不起作用:Does Spring @Transactional attribute work on a private method? 您在此处拥有的唯一一个公共方法是 execute(),因此您可以对它或整个类进行注释。

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

您可以从JobExecutionService 中删除@Transactional,将getJob()finishJob()(或应在独立事务中运行的任何方法)作为公共方法移至TransactionalJobExecutionService 等新服务,并将该新服务注释为@Transactional.

【讨论】:

    猜你喜欢
    • 2019-03-29
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多