Java 批量将实体插入数据库(Quarkus、Hibernate)
首先:我不习惯Quarkus或Hibernate(我基本上都是.net) 问题: 我的服务收到一个约10k的列表(我猜这是最常见的数字)。 这是通过一个资源端点实现的,它需要+10秒才能完成,从远到长。而且服务没有响应Java 批量将实体插入数据库(Quarkus、Hibernate),java,hibernate,vert.x,quarkus,Java,Hibernate,Vert.x,Quarkus,首先:我不习惯Quarkus或Hibernate(我基本上都是.net) 问题: 我的服务收到一个约10k的列表(我猜这是最常见的数字)。 这是通过一个资源端点实现的,它需要+10秒才能完成,从远到长。而且服务没有响应 *Endpoint -> Service/Business -> DAO* @Override public void create(FooBusiness foo) { var statuses = new ArrayList<StatusDto&
*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
公共列表创建(列表dto){
对于(var i=0;i
我已经阅读了很多关于此的帖子,其中许多帖子建议使用此属性,并将persist循环拆分为与批大小相同的大小:
问题是,当我将其添加到application.properties时,我得到了以下变量:
无法解析配置项“语句批大小”
我花了将近一天的时间试图找到如何加快速度的解决方案,有什么我在这里错过的明显的东西吗
和/或:
我是否可以将从
服务
到dao的调用包装在某种神奇的火焰中,然后忘记内置在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();
for(变量i=0;i
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();
for(变量i=0;i
除非您确定了响应时间差的确切原因,否则很难明确回答这个问题。原则上可能是由于:
与对数据库服务器的许多请求相关联的延迟
在一个Hibernate有状态会话中,或者甚至在内存中固定许多实体对象的开销
接收和解析传入数据的成本
让我们假设它不是3
- 如果是2,那么JDBC批处理确实会有所帮助,您只需要弄清楚如何使config属性工作
- 但我的猜测是Christian是正确的,问题在于持久性上下文中的数据积累。如果这个猜测是正确的,那么有两种可能的解决方案:一种是使用
无状态会话
,它的设计考虑到了这种用法,另一种是使用Christian描述的flush()
和clear()
我建议使用无状态会话
,除非问题实际上是2+3的组合,在这种情况下,您需要批处理和持久性上下文管理,在这种情况下,按照Christian的建议去做。除非你已经确定了响应时间差的确切原因,否则很难确切地回答这个问题。原则上可能是由于:
与对数据库服务器的许多请求相关联的延迟
在一个Hibernate有状态会话中,或者甚至在内存中固定许多实体对象的开销
接收和解析传入数据的成本
让我们假设它不是3
- 如果是2,那么JDBC批处理确实会有所帮助,您只需要弄清楚如何使config属性工作
- 但我的猜测是Christian是正确的,问题在于持久性上下文中的数据积累。如果这个猜测是正确的,那么有两种可能的解决方案:一种是使用
无状态会话
,它的设计考虑到了这种用法,另一种是使用Christian描述的flush()
和clear()
我建议使用无状态会话
,除非问题实际上是2+3的组合,在这种情况下,您需要批处理和持久性上下文管理,然后按照Christian的建议执行。也许您可以尝试Hibernate被动:。还有一个关于在Quarkus中使用它的快速入门:我已经非常快速地研究了它,但据我所知,它还不支持H2数据库吗?我将使用mariadb进行尝试,但我们决定使用H2作为标准,并在需要时覆盖服务器。编辑:在尝试此操作时,我一直在使用MariaDB,而不是H2。也许您可以尝试Hibernate:。还有一个关于在Quarkus中使用它的快速入门:我已经非常快速地研究了它,但据我所知,它还不支持H2数据库吗?我将使用mariadb进行尝试,但我们决定使用H2作为标准,并在需要时覆盖服务器。编辑:在尝试这个时,我一直在使用MariaDB,而不是H2。谢谢!是的,我知道在没有所有事实和数据的情况下很难指出问题所在。谢谢!是的,我知道在没有所有事实和数据的情况下很难指出问题所在。这确实加快了速度,所以我会将其标记为正确。但奇怪的是,我不能让房子运转起来。谢谢该属性是另外一种配置,用于在JDBC级别获得批处理。通常,为了获得最佳性能,最好调整使用的批次大小
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();