Java 使用Spring数据R2DBC执行大容量插入时检索生成的ID

Java 使用Spring数据R2DBC执行大容量插入时检索生成的ID,java,mysql,spring-boot,spring-webflux,spring-data-r2dbc,Java,Mysql,Spring Boot,Spring Webflux,Spring Data R2dbc,我有一个场景,我的表有一个自动生成的id列,我需要将项目批量插入数据库并获取生成的id。我有没有办法做到这一点 这是我的桌子: CREATE TABLE test_table ( `id` SERIAL NOT NULL, `name` VARCHAR(100) NOT NULL, `created_date` DATETIME NOT NULL, PRIMARY KEY (`id`) ); 要将项目列表保存到此表中,我使用的代码为: String initialSql = &

我有一个场景,我的表有一个自动生成的id列,我需要将项目批量插入数据库并获取生成的id。我有没有办法做到这一点

这是我的桌子:

CREATE TABLE test_table (
  `id` SERIAL NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `created_date` DATETIME NOT NULL,
  PRIMARY KEY (`id`)
);
要将项目列表保存到此表中,我使用的代码为:

String initialSql = "INSERT INTO test_table(`name`,`created_date`) VALUES ";

    List<String> values =
        dummyEntities.stream()
            .map(dummyEntity -> "('" + dummyEntity.getName() + "','"
                + dummyEntity.getCreatedDate().atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime().toString() + "')")
            .collect(Collectors.toList());

    String sqlToExecute =  initialSql + String.join(",", values);
    client.execute(sqlToExecute)
             .//Then what?
我甚至尝试过使用
连接工厂
,但仍然没有任何线索

    Mono.from(connectionFactory.create())
        .map(Connection::createBatch)
        .map(batch -> {
          dummyEntities.forEach(dummyEntity -> {
            String sql = String.format("INSERT INTO `test_table` (`name`,`created_date`) VALUES ('%s','%s');", dummyEntity.getName(),
                dummyEntity.getCreatedDate().atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime().toString());
            batch.add(sql);
          });
          return batch;
        })
        .flatMap(batch -> Mono.from(batch.execute()))
        .//Then what?
作为参考,
dummeyentities
变量包含
dummeyentity
对象的列表。而
dummeyentity
类如下所示:

@Table("test_table")
public class DummyEntity implements Persistable<Long> {

  @Id
  @Column("id")
  private Long id;

  @Column("name")
  private String name;

  @Column("created_date")
  private OffsetDateTime createdDate;

  //Getter,Setter
  @Override
  public boolean isNew() {
    return id == null;
  }
}

使用原始的
连接factory
很容易获得生成的ID

我尝试使用
ConnectionFactory
获取生成的ID,并按预期工作

。然后很多(
单声道,从(康涅狄格州)
flatMapMany先生(
c->c.createStatement(插入SQL)
.returnGeneratedValues(“id”)
.execute()
)
)
.flatMap(data->Flux.from(data.map((行,行元数据)->row.get(“id”))
.doOnNext(id->log.info(“生成的id:{}”,id))
完整的代码示例如下所示

它像这样在控制台中打印日志

2020-09-19 10:43:30815 INFO[main]com.example.demo.H2Tests$Sql:89生成的id:1
2020-09-19 10:43:30815 INFO[main]com.example.demo.H2Tests$Sql:89生成的id:2
我认为SpringFramework5.3中新的
DatabaseClient
只是ConnectionFactorys的一个薄包装,并使用
filter
获得生成的ID

databaseClient.sql(“插入帖子(标题、内容、元数据)值(:标题、内容、元数据)”)
.filter((语句,executeFunction)->语句.returnGeneratedValues(“id”).execute()

检查(但本例仅检索单个id)。

使用原始的
连接facotory
很容易获得生成的id

我尝试使用
ConnectionFactory
获取生成的ID,并按预期工作

。然后很多(
单声道,从(康涅狄格州)
flatMapMany先生(
c->c.createStatement(插入SQL)
.returnGeneratedValues(“id”)
.execute()
)
)
.flatMap(data->Flux.from(data.map((行,行元数据)->row.get(“id”))
.doOnNext(id->log.info(“生成的id:{}”,id))
完整的代码示例如下所示

它像这样在控制台中打印日志

2020-09-19 10:43:30815 INFO[main]com.example.demo.H2Tests$Sql:89生成的id:1
2020-09-19 10:43:30815 INFO[main]com.example.demo.H2Tests$Sql:89生成的id:2
我认为SpringFramework5.3中新的
DatabaseClient
只是ConnectionFactorys的一个薄包装,并使用
filter
获得生成的ID

databaseClient.sql(“插入帖子(标题、内容、元数据)值(:标题、内容、元数据)”)
.filter((语句,executeFunction)->语句.returnGeneratedValues(“id”).execute()

检查(但本例仅检索单个id)。

稍后的响应,但由于我在R2DBC PostgreSQL上遇到了相同的问题,因此有一个可能的解决方案:

// -- generate 100 Product entities and mark them as CREATE
// -- Product is implementing Persistable<UUID> and isNew() will return TRUE for CREATE and FALSE for UPDATE 
List<Product> list = Stream.generate(() -> Product.builder()
    .articleNumber(UUID.randomUUID().toString().substring(0, 10))
    .name(UUID.randomUUID().toString())
    .images(Arrays.asList("1", "2"))
    .saveAction(SaveAction.CREATE)
    .build()).limit(100).collect(Collectors.toList());

// -- create the PostgresqlBatch and return the Result flux
Flux<? extends Result> flux = databaseClient.inConnectionMany(connection -> {
  Batch batch = connection.createBatch();

  list.forEach(p -> {
    batch.add("INSERT INTO product(\"id\",\"article_number\",\"name\") VALUES ('" + p.getId() + "','" + p.getArticleNumber() + "','" + p
        .getName() + "') RETURNING id, name, article_number");
  });

  return Flux.from(batch.execute());
});

// -- transform the Result flux into a Product flux
return flux.flatMap(result -> result.map((row, rowMetadata) -> Product.builder()
    .id(row.get("id", UUID.class))
    .name(row.get("name", String.class))
    .articleNumber(row.get("article_number", String.class))
    .build()));
/--生成100个产品实体并将其标记为CREATE
//--产品正在实现Persistable,isNew()将为CREATE返回TRUE,为UPDATE返回FALSE
List List=Stream.generate(()->Product.builder()
.articleNumber(UUID.randomUUID().toString().substring(0,10))
.name(UUID.randomUUID().toString())
.images(数组.asList(“1”、“2”))
.saveAction(saveAction.CREATE)
.build()).limit(100.collect(Collectors.toList());
//--创建PostgresqlBatch并返回结果

Flux稍后的响应,但由于我在R2DBC PostgreSQL上遇到了相同的问题,下面是一个可能的解决方案:

// -- generate 100 Product entities and mark them as CREATE
// -- Product is implementing Persistable<UUID> and isNew() will return TRUE for CREATE and FALSE for UPDATE 
List<Product> list = Stream.generate(() -> Product.builder()
    .articleNumber(UUID.randomUUID().toString().substring(0, 10))
    .name(UUID.randomUUID().toString())
    .images(Arrays.asList("1", "2"))
    .saveAction(SaveAction.CREATE)
    .build()).limit(100).collect(Collectors.toList());

// -- create the PostgresqlBatch and return the Result flux
Flux<? extends Result> flux = databaseClient.inConnectionMany(connection -> {
  Batch batch = connection.createBatch();

  list.forEach(p -> {
    batch.add("INSERT INTO product(\"id\",\"article_number\",\"name\") VALUES ('" + p.getId() + "','" + p.getArticleNumber() + "','" + p
        .getName() + "') RETURNING id, name, article_number");
  });

  return Flux.from(batch.execute());
});

// -- transform the Result flux into a Product flux
return flux.flatMap(result -> result.map((row, rowMetadata) -> Product.builder()
    .id(row.get("id", UUID.class))
    .name(row.get("name", String.class))
    .articleNumber(row.get("article_number", String.class))
    .build()));
/--生成100个产品实体并将其标记为CREATE
//--产品正在实现Persistable,isNew()将为CREATE返回TRUE,为UPDATE返回FALSE
List List=Stream.generate(()->Product.builder()
.articleNumber(UUID.randomUUID().toString().substring(0,10))
.name(UUID.randomUUID().toString())
.images(数组.asList(“1”、“2”))
.saveAction(saveAction.CREATE)
.build()).limit(100.collect(Collectors.toList());
//--创建PostgresqlBatch并返回结果

Flux您要查找的是
client.execute(…).all()
记录在这里,这取决于您返回不同对象的查询,但我认为您要查找的是
all()
。您要查找的是
client.execute(…).all()
这里的文档记录取决于您返回的不同对象的查询,但我认为它是您正在寻找的
all()
。您好@Hantsy,很抱歉响应太晚。我试过你的密码。但它只返回一个生成的id(批处理的第一个id)。在这里查看:。您能指出我在这里做错了什么吗?不确定代码中的确切原因,无法从代码片段中确定。我试过我的代码,它工作正常。你使用的是同一个Miku Mysql驱动程序吗?从您共享的代码片段来看,它是针对H2的。尝试了MySQL,是的,它只返回最后一个id。可能是来自语句
last\u insert\u id
。是的,非反应驱动程序如何返回所有生成的id?一定有办法……是不是@Hantsy?嗨@Hantsy,很抱歉这么晚才回复。我试过你的密码。但它只返回一个生成的id(批处理的第一个id)。
// -- generate 100 Product entities and mark them as CREATE
// -- Product is implementing Persistable<UUID> and isNew() will return TRUE for CREATE and FALSE for UPDATE 
List<Product> list = Stream.generate(() -> Product.builder()
    .articleNumber(UUID.randomUUID().toString().substring(0, 10))
    .name(UUID.randomUUID().toString())
    .images(Arrays.asList("1", "2"))
    .saveAction(SaveAction.CREATE)
    .build()).limit(100).collect(Collectors.toList());

// -- create the PostgresqlBatch and return the Result flux
Flux<? extends Result> flux = databaseClient.inConnectionMany(connection -> {
  Batch batch = connection.createBatch();

  list.forEach(p -> {
    batch.add("INSERT INTO product(\"id\",\"article_number\",\"name\") VALUES ('" + p.getId() + "','" + p.getArticleNumber() + "','" + p
        .getName() + "') RETURNING id, name, article_number");
  });

  return Flux.from(batch.execute());
});

// -- transform the Result flux into a Product flux
return flux.flatMap(result -> result.map((row, rowMetadata) -> Product.builder()
    .id(row.get("id", UUID.class))
    .name(row.get("name", String.class))
    .articleNumber(row.get("article_number", String.class))
    .build()));