批量将实体插入数据库(Quarkus、Hibernate)



首先:我不习惯Quarkus或Hibernate(我几乎都是.net(

问题:

我的服务收到一个约10k的列表(我想这是最常见的数字(。这是通过一个资源端点实现的,它需要+10s才能完成,从远到长。服务没有响应。

*Endpoint -> Service/Business -> DAO*
@Override
public void create(FooBusiness foo) {
var statuses = new ArrayList<StatusDto>();
for(var i = 1; i < foo.getFromList().size(); i++){
var bar = foo.getFromList().get(i);
statuses.add(new StatusDto(bar.x, bar.y));
}
statusDao.create(statuses);
}

statusDao.Create((用@Transactional:进行注释

DAO是@ApplicationScoped

这个EM是:

@PersistenceContext
EntityManager entityManager;

statusDao.Create((:

@Transactional
public List<StatusDto> create(List<StatusDto> dto) {
for(var i = 0; i < dto.size(); i++){
var status = dto.get(i);
status.setCreatedTimestamp(LocalDateTime.now());
entityManager.persist(status);
}
entityManager.flush();
return dto;
}

我已经读了很多关于这方面的文章,其中许多都建议使用这个属性,并将持久循环拆分为与批大小相同:quarkus.hibernate-orm.jdbc.statement-batch-size

问题是,当我把它添加到application.properties时,我得到了这个varning:

无法解析配置项"语句批量大小">

我花了将近一天的时间试图找到如何加快速度的解决方案,我在这里错过了什么?

和/或:

我可以用某种神奇的火包装从servicedao的调用并忘记Quarkus或Vert.x中内置的调用吗?

Hibernate会将您持久化的所有实体保留在持久化上下文中,这样您将获得越来越多的内存,这可能会导致性能不佳。如果你不再像看起来那样需要这些实体,你可以将它们清除,例如一批50件。

for (var i = 0; i < dto.size();) {
var status = dto.get(i);
status.setCreatedTimestamp(LocalDateTime.now());
entityManager.persist(status);
i++;
if ((i % 50) == 0) {
entityManager.flush();
entityManager.clear();
}
}
entityManager.flush();

除非您已经确定了响应时间差的确切原因,否则很难明确回答这个问题。原则上可能是由于:

  1. 与对数据库服务器的许多请求相关联的延迟
  2. 在Hibernate有状态会话中将许多实体对象固定在内存中的开销,甚至
  3. 接收和解析传入数据的成本

让我们假设它不是3。

  • 如果是2,那么JDBC批处理确实会有所帮助,您只需要弄清楚如何使配置属性工作即可
  • 但我的猜测是克里斯蒂安是正确的,问题是持久性环境中数据的积累。如果这个猜测是正确的,那么有两种可能的解决方案:一种是使用StatelessSession,它是在设计时考虑到这种用法的,另一种是如Christian所述使用flush()clear()

我建议使用StatelessSession,除非问题实际上是2+3的组合,在这种情况下,您需要同时进行批处理、持久性上下文管理,然后按照Christian的建议执行。

相关内容

  • 没有找到相关文章

最新更新