spring 如何在r2dbc中批量执行多个插入?

yrdbyhpb  于 2023-03-28  发布在  Spring
关注(0)|答案(3)|浏览(283)

我需要在一个批处理中将多行插入到一个表中。在DatabaseClient中,我发现insert()语句和using(Publisher objectToInsert)方法有多个对象作为参数。但是它会在一个批处理中插入它们吗?另一个可能的解决方案是connection.createBatch(),但它有一个drowback:我不能在那里传递我的Entity对象,也不能从实体生成sql查询。
那么,是否可以在r2dbc中创建批插入?

vhipe2zx

vhipe2zx1#

到目前为止还没有直接的支持,但是我发现可以使用Connection来简单地克服这个障碍,请查看这个问题,spring-data-r2dbc#259
statement有一个add来重复绑定参数。
我的解决方案的完整代码可以在这里找到。

return this.databaseClient.inConnectionMany(connection -> {

            var statement = connection.createStatement("INSERT INTO  posts (title, content) VALUES ($1, $2)")
                    .returnGeneratedValues("id");

            for (var p : data) {
                statement.bind(0, p.getTitle()).bind(1, p.getContent()).add();
            }

            return Flux.from(statement.execute()).flatMap(result -> result.map((row, rowMetadata) -> row.get("id", UUID.class)));
        });

对这种方法的测试。

@Test
    public void testSaveAll() {

        var data = Post.builder().title("test").content("content").build();
        var data1 = Post.builder().title("test1").content("content1").build();

        var result = posts.saveAll(List.of(data, data1)).log("[Generated result]")
                .doOnNext(id->log.info("generated id: {}", id));

        assertThat(result).isNotNull();
        result.as(StepVerifier::create)
                .expectNextCount(2)
                .verifyComplete();
    }

生成的id按预期在控制台中打印。

...
2020-10-08 11:29:19,662 INFO [reactor-tcp-nio-2] reactor.util.Loggers$Slf4JLogger:274 onNext(a3105647-a4bc-4986-9ad4-1e6de901449f)
2020-10-08 11:29:19,664 INFO [reactor-tcp-nio-2] com.example.demo.PostRepositoryTest:31 generated id: a3105647-a4bc-4986-9ad4-1e6de901449f
//.....
2020-10-08 11:29:19,671 INFO [reactor-tcp-nio-2] reactor.util.Loggers$Slf4JLogger:274 onNext(a611d766-f983-4c8e-9dc9-fc78775911e5)
2020-10-08 11:29:19,671 INFO [reactor-tcp-nio-2] com.example.demo.PostRepositoryTest:31 generated id: a611d766-f983-4c8e-9dc9-fc78775911e5
//......

Process finished with exit code 0
sg3maiej

sg3maiej2#

有两个问题:
DatabaseClient.insert()是否会将它们插入一个批次中?
不是一批。
是否可以在r2dbc中创建批量插入?(Connection.createBatch()除外)
不,使用Connection.createBatch()只是为 now 创建Batch的一种方法。
另见问题:

nzkunb0c

nzkunb0c3#

不幸的是,仍然没有内置的支持。我对@Hantsy的回答的唯一问题是,我得到了错误No unfinished bindings!
以下是调整后的工作解决方案(最后一次绑定时没有statement.add()

public class Post {
        @Id
        private Integer id;
        private String title;
        private String post;
    }
    
    public Flux<Post> saveAll(List<Post> postList) {
        return databaseClient.inConnectionMany(connection -> {
            Statement statement = connection.createStatement("insert into POST (TITLE, POST) " +
                            " VALUES ($1, $2)")
                    .returnGeneratedValues("ID", "TITLE", "POST");
            for (int i = 0; i < postList.size(); ) {
                Post post = postList.get(i);
                statement.bind(0, post.getTitle())
                        .bind(1, post.getPost());
                if (++i < postList.size()) {
                    statement.add();
                }
            }

            return Flux.from(statement.execute())
                    .flatMap(result -> (Flux<Post>) result.map((row, rowMetadata) -> {
                        Integer id = row.get("ID", Integer.class);
                        String post = row.get("POST", String.class);
                        String title = row.get("TITLE", String.class);
                        return new Post(id, post, title);
                    }));
        });
    }

相关问题