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

问题描述 投票:0回答:3

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

问题:

我的服务收到约 10k 的列表(我猜这是最常见的数字)。 这是通过资源端点实现的,需要 10 秒以上才能完成,时间太长了。并且服务没有响应。

*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 时,我得到这个警告:

无法解析配置项“statement-batch-size”

我花了几乎一天的时间试图找到如何加快速度的解决方案,有什么明显的我在这里错过的吗?

和/或:

我可以将从

service
dao
的调用包装在 Quarkus 或 Vert.x 中内置的某种神奇的火并忘记调用中吗?

java hibernate vert.x quarkus
3个回答
4
投票

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

2
投票

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

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

我们假设不是 3。

  • 如果是 2,那么 JDBC 批处理确实会有所帮助,您只需要弄清楚如何使该配置属性发挥作用。
  • 但我的猜测是 Christian 是正确的,问题在于持久化上下文中的数据积累。如果这个猜测是正确的,那么有两种可能的解决方案:一种是使用
    StatelessSession
    ,它是为这种用法而设计的,另一种是使用 Christian 描述的
    flush()
    clear()

我建议使用

StatelessSession
除非问题实际上是2+3的组合,在这种情况下你需要两者批处理,持久上下文管理,然后在这种情况下按照Christian的建议去做。


0
投票

您可以将

quarkus.hibernate-orm.jdbc.statement-batch-size
配置设置为 > 0(建议值在 5 到 30 之间)。这使得 Hibernate 能够进行 JDBC2 批量更新。请参阅this博客文章了解详细信息和基准。

© www.soinside.com 2019 - 2024. All rights reserved.