为什么 Hibernate 不批量插入用 @ElementCollection 注释的字段?

mic*_*mia 7 java hibernate spring-boot spring-boot-jpa

我有一个@Entity包含一些@OneToMany关系,但由于它们由 s 的集合组成Enum,所以我使用@ElementCollection. 该实体有一个在数据库级别 (MySQL) 生成的 ID。

这是我刚刚编写的一个小示例,它对应于我的实体的结构。

@Entity
public class Student {

  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @ElementCollection(targetClass = Language.class)
  @CollectionTable(name="student_languages", joinColumns=@JoinColumn(name="student_id"))
  private Set<Language> languages;

  @ElementCollection(targetClass = Module.class)
  @CollectionTable(name="student_modules", joinColumns=@JoinColumn(name="student_id"))
  private Set<Module> modules;

  @ElementCollection(targetClass = SeatPreference.class)
  @CollectionTable(name="student_seats", joinColumns=@JoinColumn(name="student_id"))
  private Set<SeatPreference> seatPreference;

[...]
}
Run Code Online (Sandbox Code Playgroud)

我知道这GenerationType.IDENTITY会停用批处理,但我认为这仅适用于主要实体,而不适用于单个属性。我必须批量导入一些实体(~20k),每个实体都有一些属性,但是 Hibernate 似乎为集合中的每个属性生成一个插入,使得导入速度慢得难以置信(每个实体需要 10 到 20 个插入)记录)。

我现在花了很长时间试图加快速度,以至于我正在考虑生成一个可以手动导入数据库的 SQL 文件。

有没有办法指示Hibernate批量插入字段@ElementCollection?难道我做错了什么?

Bab*_*abl 3

基本上,hibernate 似乎对批处理没有帮助@ElementCollection ,但您可以使用 SQL批量插入。看来您使用的 MySQL 确实支持批量插入,并且如果您启用该属性,它的 JDBC 驱动程序可以自动将各个插入语句修改/重写为一个批量语句 rewriteBatchedStatements

因此,在您的情况下,您需要做的是告诉 hibernate 启用批处理并订购批量插入和更新。

hibernate.jdbc.batch_size=100
hibernate.order_inserts=true
hibernate.order_updates=true
Run Code Online (Sandbox Code Playgroud)

这将确保在将数据插入数据库时​​,Hibernate生成的插入语句将批量执行,并且它们是有序的。

所以 Hibernate 生成的 SQL 会是这样的:

insert into student_languages (student_id, languages) values (1,1)
insert into student_languages (student_id, languages) values (1,2)
insert into student_languages (student_id, languages) values (1,3)
insert into student_languages (student_id, languages) values (1,4)
Run Code Online (Sandbox Code Playgroud)

接下来,您需要告诉 JDBC 驱动程序通过设置以下内容将单个插入重写为批量插入:rewriteBatchedStatements=true

jdbc:mysql://db:3306/stack?useSSL=false&rewriteBatchedStatements=true
Run Code Online (Sandbox Code Playgroud)

所以这会指示驱动程序将插入重写为批量形式,因此上面的几个SQL语句将被重写为这样的内容

insert into student_languages (student_id, languages) values (1,1),(1,2),(1,3),(1,4)
Run Code Online (Sandbox Code Playgroud)

作为一个信息,如果您使用旧版本的 MySQL 驱动程序和 Hibernate,这可能不起作用。