JPA储存库和阻止的I / O

时间:2019-05-24 14:18:54

标签: java spring-boot spring-data-jpa

我遇到一个问题,在使用JpaRepository写入数据库后,我需要在单独的线程上执行几个缓慢的HTTP请求。问题是doActualJob()在等待一系列期货结算时发生冻结。这似乎阻止了基础的Hibernate会话关闭,从而导致应用程序不久后耗尽连接。

如何编写此函数,以便在执行阻塞I / O时不会保持数据库连接打开?甚至可以使用JpaRepositories,还是我需要使用诸如EntityManager / SessionFactory之类的较低级别的API?

@Service
class SomeJobRunner {

    private final SomeJobRepository mSomeJobRepository; //extends JpaRepository

    @AutoWired
    public SomeJobRunner(final SomeJobRepository someJobRepository) {
        mSomeJobRepository = someJobRepository;
    }

    @Async
    public void doSlowJob(final long someJobId) {
        SomeJob someJob = mSomeJobRepository.findOne(someJobId);
        someJob.setJobStarted(Instant.now());
        mSomeJobRepository.saveAndFlush(someJob);

        doActualjob(); // Synchronous job doing several requests using Unirest in series

        someJob = mSomeJobRepository.findOne(someJobId);
        someJob.setJobEnded(Instant.now());
        mSomeJobRepository.saveAndFlush(someJob);
}

2 个答案:

答案 0 :(得分:3)

好吧-在Java / JDBC世界中,以标准方式不可能实现非阻塞数据库IO。简单地说-您的Spring数据存储库最终将使用JPA ORM实现(例如Hibernate),而该实现又将使用JDBC与本质上是阻塞的数据库进行交互。 Oracle(Asynchronous Database Access API)目前正在对此进行工作,以提供与JDBC类似的API,但没有阻塞。他们打算将此作为标准提出。 Spring团队在R2DBC – Reactive Relational Database Connectivity上也进行了令人兴奋的并行工作。他们实际上也已将其与Spring数据(link)集成在一起,因此可以帮助您集成到解决方案中。可以在here上找到Spring撰写的一篇很好的教程。

答案 1 :(得分:-1)

我建议使用单独的JTA transaction来写数据库。这样做,定义一个

之类的方法
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void saveJobStart(final long someJobId) {
    SomeJob someJob = mSomeJobRepository.findOne(someJobId);
    someJob.setJobStarted(Instant.now());
    mSomeJobRepository.saveAndFlush(someJob);
}

当然不是完全一样。如果doActualjob()失败,则您的数据库将不会保留开始日期。在我的建议中,它将坚持下去。为了进行补偿,您需要在新交易中删除 doSlowJob catch组中的开始日期,然后重新throw例外。