使用 inMemory 数据库时出现 R2dbc H2 问题

Han*_*tsy 5 spring-boot project-reactor spring-webflux spring-data-r2dbc r2dbc

我试图品尝 R2dbc 并使用嵌入式 H2,例如:

public ConnectionFactory connectionFactory() {
        //ConnectionFactory factory = ConnectionFactories.get("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
        return new H2ConnectionFactory(
                H2ConnectionConfiguration.builder()
                        //.inMemory("testdb")
                        .file("./testdb")
                        .username("user")
                        .password("password").build()
        );
    }

Run Code Online (Sandbox Code Playgroud)

我定义了一个 bean 来创建表和初始化数据。

@Bean
    public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {

        ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
        initializer.setConnectionFactory(connectionFactory);

        CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
        populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
        populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("data.sql")));
        initializer.setDatabasePopulator(populator);

        return initializer;
    }
Run Code Online (Sandbox Code Playgroud)

而且我还定义了另一个组件来通过java代码设置数据。


@Component
@Slf4j
class DataInitializer {

    private final DatabaseClient databaseClient;

    public DataInitializer(DatabaseClient databaseClient) {
        this.databaseClient = databaseClient;
    }

    @EventListener(value = ContextRefreshedEvent.class)
    public void init() {
        log.info("start data initialization  ...");
        this.databaseClient.insert()
            .into("posts")
            //.nullValue("id", Integer.class)
            .value("title", "First post title")
            .value("content", "Content of my first post")
            .map((r, m) -> r.get("id", Integer.class))
            .all()
            .log()
            .thenMany(
                this.databaseClient.select()
                    .from("posts")
                    .orderBy(Sort.by(desc("id")))
                    .as(Post.class)
                    .fetch()
                    .all()
                    .log()
            )
            .subscribe(null, null, () -> log.info("initialization done..."));
    }

}
Run Code Online (Sandbox Code Playgroud)

如果我.inMemory("testdb")ConnectionFactorybean 定义中使用,当 SpringApplicationContext初始化时,它失败了,因为在初始化时找不到表POSTSDataInitializer。从启动日志来看,ConnectionFactoryInitializer初始化成功,并通过执行schema.sql和data.sql创建表POSTS并按预期插入数据。

但是切换到 use .file("./testdb"),它起作用了。

完整的代码在这里

Han*_*tsy 7

我从 Spring Data R2dc 开发人员 @mp911de 那里得到了答案。请参阅#issue269

\n\n
\n

该问题与 H2\xe2\x80\x98s 在最后一个连接关闭时关闭数据库的行为有关。请配置 DB_CLOSE_DELAY=-1 选项,以便 H2 保留数据库。或者,使用 H2ConnextionFactory.inMemory(...) 工厂方法创建一个不依赖于正在使用的连接计数的 Closeable 连接工厂。

\n
\n\n

将我的代码更改为以下内容,它可以工作:

\n\n
\n public ConnectionFactory connectionFactory() {       \n     return H2ConnectionFactory.inMemory("testdb");\n }\n
Run Code Online (Sandbox Code Playgroud)\n