当前位置: 首页 > 面试题库 >

Spring Data JPA:批量插入嵌套实体

韦翰音
2023-03-14
问题内容

我有一个测试用例,需要将100‘000个实体实例持久存储到数据库中。我当前使用的代码可以做到这一点,但是要花40秒才能将所有数据持久保存在数据库中。从大小约为15
MB的JSON文件中读取数据。

现在,在另一个项目之前,我已经在自定义存储库中实现了批量插入方法。但是,在那种情况下,我要保留许多顶级实体,而只有少数嵌套实体。

在我目前的情况下,我有5个Job实体,其中包含约30个JobDetail实体的列表。其中一个JobDetail包含850至1100个JobEnvelope实体。

当写入数据库时​​,我Job使用默认save(Iterable<Job> jobs)接口方法提交实体列表。所有嵌套实体均具有CascadeType
PERSIST。每个实体都有自己的表。

启用批处理插入的通常方法是实现一个自定义方法saveBatch,该方法每隔一段时间刷新一次。但是在这种情况下,我的问题是JobEnvelope实体。我不使用JobEnvelope存储库来持久化它们,而是让Job实体的存储库来处理它。我正在使用MariaDB作为数据库服务器

因此,我的问题可以归结为以下几点:如何将JobRepository插入的嵌套实体批量化?

这些是我所讨论的3个实体:

工作

@Entity
public class Job {
  @Id
  @GeneratedValue
  private int jobId;

  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "job")
  @JsonManagedReference
  private Collection<JobDetail> jobDetails;
}

工作细节

@Entity
public class JobDetail {
  @Id
  @GeneratedValue
  private int jobDetailId;

  @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
  @JoinColumn(name = "jobId")
  @JsonBackReference
  private Job job;

  @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "jobDetail")
  @JsonManagedReference
  private List<JobEnvelope> jobEnvelopes;
}

作业信封

@Entity
public class JobEnvelope {
  @Id
  @GeneratedValue
  private int jobEnvelopeId;

  @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
  @JoinColumn(name = "jobDetailId")
  private JobDetail jobDetail;

  private double weight;
}

问题答案:

确保正确配置与Hibernate批处理相关的属性:

<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>

关键是,如果连续语句操作同一张表,则可以对其进行批处理。如果出现要插入另一个表的语句,则必须在该语句之前中断并执行先前的批处理构造。使用该hibernate.order_inserts属性,您可以允许Hibernate在构造批处理语句之前对插入进行重新排序(hibernate.order_updates对update语句具有相同的作用)。

jdbc.batch_size是Hibernate将使用的最大批处理大小。尝试分析不同的值,然后选择一个在您的用例中表现出最佳性能的值。

请注意,如果使用id生成器,则将禁用插入语句的批处理IDENTITY

特定于MySQL,您必须指定rewriteBatchedStatements=true作为连接URL的一部分。为确保批处理按预期方式工作,请添加profileSQL=true以检查驱动程序发送到数据库的SQL。

如果您的实体已版本化(出于乐观锁定目的),那么为了利用批量更新(不影响插入),您还必须打开:

<property name="hibernate.jdbc.batch_versioned_data">true</property>

使用此属性,您可以告诉Hibernate在执行批处理更新(需要执行版本检查)时JDBC驱动程序能够返回受影响行的正确计数。您必须检查这对于您的数据库/
jdbc驱动程序是否正常工作。例如,它不适用于Oracle11和更早的Oracle版本。

您可能还希望在每个批处理之后刷新并清除持久性上下文以释放内存,否则所有托管对象都将保留在持久性上下文中,直到将其关闭。

另外,您可能会发现此博客很有用,因为它很好地解释了Hibernate批处理机制的详细信息。



 类似资料:
  • 我有一个测试用例,需要将100,000个实体实例持久化到数据库中。我当前使用的代码就是这样做的,但直到将所有数据持久化到数据库中为止,最多需要40秒。数据是从一个大约15 MB大小的JSON文件中读取的。 现在,我已经为另一个项目在自定义存储库中实现了批处理插入方法。但是,在这种情况下,我有很多顶级实体要持久化,只有几个嵌套实体。 在我当前的例子中,我有5个实体,这些实体包含大约30个实体的列表。

  • 我正在写一个数据挖掘程序,可以批量插入用户数据。 当前SQL只是一个普通的批量插入: 如果发生冲突,如何进行更新?我试过: 但它抛出

  • 问题内容: 这是我在阅读有关jpa批量插入的几个主题之后创建的简单示例,我有2个持久对象User和Site。一个用户可以拥有多个站点,因此我们在这里有一对多的关系。假设我要创建用户并将多个站点创建/链接到用户帐户。考虑到我愿意为Site对象使用批量插入,代码如下所示。 但是,当我运行此代码时(我将hibernate方式用作jpa实现提供程序),我看到以下sql输出: 所以,我的意思是“真实的”批量

  • 问题内容: 我正在使用Python中的MySQLdb模块与数据库进行交互。我遇到的情况是有一个非常大的列表(成千上万个元素),需要将它们作为行插入表中。 我现在的解决方案是生成一个大的语句作为字符串并执行它。 有没有更聪明的方法? 问题答案: 有一种更聪明的方法。 批量插入的问题在于,默认情况下启用了自动提交功能,从而导致每个语句在下一次插入可以启动之前被保存到稳定存储中。 如手册页所述: 默认情

  • 问题内容: 我正在尝试将数据从此链接插入到我的SQL Server https://www.ian.com/affiliatecenter/include/V2/CityCoordinatesList.zip 我创建了表 我正在运行以下脚本来进行批量插入 但是批量插入失败,并出现以下错误 当我使用google时,我发现了几篇文章,指出问题可能出在RowTerminator上,但我尝试了诸如/ n

  • 我尝试使用r2dbc执行批处理插入。 我已经看到,使用spring boot中的DatabaseClient,这还不可能实现。我尝试使用R2DBC SPI语句和and方法来实现这一点,如下所示: 我在日志上看到完成了两个插入请求。 添加是执行批更新还是只运行两个请求? 谢谢