我遇到一个问题,在使用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);
}
答案 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
例外。