有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring Boot JPA是否可以使用IDENTITY generator或等效程序进行批插入?

我最近发现了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接收(循环请求路由)。将引发以下异常:
    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


共 (1) 个答案

  1. # 1 楼答案

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

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

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

        @Id
        @GeneratedValue
        private UUID id;
    

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

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