【问题标题】:Spring Boot JPA - Is it possible to batch insert with IDENTITY generator or equivelant?Spring Boot JPA - 是否可以使用 IDENTITY 生成器或等效工具批量插入?
【发布时间】:2020-11-30 12:32:45
【问题描述】:

我最近才发现在 Spring Boot JPA 2.2.6 和 Mysql 8 中批量插入。

要使批量插入工作,我必须更改以下内容:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private long id;

到:

@Id
@GeneratedValue(generator = "generator")
@GenericGenerator(name = "generator", strategy = "increment")
@Column(name = "id", unique = true, nullable = false)
private long id;

带有一些附加属性:

spring:
  jpa:
    properties:
      hibernate:
        generate_statistics: true
        jdbc:
          batch_size: 1000
        order_inserts: true
        order_updates: true

当我使用单个服务器实例进行测试时,批量插入似乎正在工作。但我刚刚注意到,当有两个 API 实例时,id 递增无法正常工作。

似乎正在发生的事情是:

  1. POST 创建实体并将其持久保存在 MySQL 数据库中。请求由实例 1 接收。实体获取 id 1。
  2. POST 创建实体并将其持久保存在 MySQL 数据库中。请求被实例 2(Round Robin 请求路由)接收。抛出以下异常:
    Aug 10 20:47:00 ip-10-1-0-120.dev.dev.uk bash[25107]: 2020-08-10 20:47:00.408  INFO 25107 --- [nio-8080-exec-4] o.h.e.j.b.internal.AbstractBatchImpl     : HHH000010: On release of batch it still contained JDBC statements
    Aug 10 20:47:00 ip-10-1-0-120.dev.dev.uk bash[25107]: 2020-08-10 20:47:00.410 ERROR 25107 --- [nio-8080-exec-4] o.h.e.jdbc.batch.internal.BatchingBatch  : HHH000315: Exception executing batch [java.sql.BatchUpdateException: Duplicate entry '1' for key 'PRIMARY'], SQL: insert into REMINDER (deleted, created, created_by, last_modified, last_modified_by, context, notification_type, reminder_date, user_id, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    Aug 10 20:47:00 ip-10-1-0-120.dev.dev.uk bash[25107]: 2020-08-10 20:47:00.411  WARN 25107 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1062, SQLState: 23000
    Aug 10 20:47:00 ip-10-1-0-120.dev.dev.uk bash[25107]: 2020-08-10 20:47:00.412 ERROR 25107 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper   : Duplicate entry '1' for key 'PRIMARY'

当我想使用批量插入时,如何防止在使用多个实例时引发重复键异常,同时确保每个新实体始终在多个实例中获取下一个可用的递增 id?

【问题讨论】:

  • 您必须将其从 long 更改为 Long 因为原语不能为空,但 Long 可以。将您的 id 设置为 null,只要您在数据库中正确设置它以增加 id,spring 将自动为其获取下一个 id。

标签: java mysql spring spring-boot jpa


【解决方案1】:

GenerationType.IDENTITY 不允许批量插入。你可以看到这个,例如here

确实,当使用多个实例时,此代码将不起作用。因为策略 increment 使用 IncrementGenerator 实现。在那里您可以看到数据库中的最大 ID 值已被缓存。因此,如果应用程序的另一个实例插入了一个值,那么当前实例永远不会知道它。

要解决您的问题,您可以使用

    @Id
    @GeneratedValue
    private UUID id;

或者您应该将数据库更改为 PostgreSQL,然后您必须使用sequence 策略。

如果这些选项不适合您,您可以在DefaultIdentifierGeneratorFactory 中查看其他生成标识符的策略的实现

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-17
    • 2019-06-01
    • 2018-11-14
    • 1970-01-01
    • 2014-11-14
    • 2018-07-08
    • 2021-07-05
    • 1970-01-01
    相关资源
    最近更新 更多