【问题标题】:R2dbc H2 issues when using inMemory database使用 inMemory 数据库时出现 R2dbc H2 问题
【发布时间】:2020-04-23 02:25:36
【问题描述】:

我尝试体验 R2dbc 并使用 Embedded 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()
        );
    }

我定义了一个 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;
    }

我还定义了另一个组件,通过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..."));
    }

}

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

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

完整代码为here

【问题讨论】:

    标签: spring-boot spring-webflux project-reactor spring-data-r2dbc r2dbc


    【解决方案1】:

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

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

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

    
     public ConnectionFactory connectionFactory() {       
         return H2ConnectionFactory.inMemory("testdb");
     }
    

    【讨论】:

      【解决方案2】:

      来自官方文档

      ConnectionFactory

      @Configuration
      public class ApplicationConfiguration extends AbstractR2dbcConfiguration {
      
        @Override
        @Bean
        public ConnectionFactory connectionFactory() {
          return …;
        }
      }
      

      这种方法让您可以使用标准的 io.r2dbc.spi.ConnectionFactory 例如,容器使用 Spring 的 AbstractR2dbc 配置。相比注册一个 ConnectionFactory 实例直接,配置支持有 还为容器提供了一个额外的优势 将 R2DBC 异常转换为的 ExceptionTranslator 实现 Spring 的可移植 DataAccessException 数据层次结构中的异常 访问使用@Repository 注解注解的类。

      (...)

      AbstractR2dbcConfiguration 还注册了 DatabaseClient,这是数据库交互和 Repository 实现所必需的。

      我写了一篇关于如何设置 R2DBC 入门的博客文章hereHere是一个使用H2数据库的例子

      我的猜测是您没有正确初始化连接工厂,因此没有获得正确的 DatabaseClient。

      【讨论】:

      • 我不这么认为。从启动日志看,ConnectionFactory 没问题,ConnectionFactoryInitializer 初始化成功(创建和插入数据),但是当初始化 DataInitializer 插入另一个数据时,由于找不到表“posts”而失败。我提到使用.file("./testdb") 而不是InMemory,它可以工作。
      • 好吧显然不是这样,否则你不会在这里写。
      • @ThomasAndolf ,在您的文章中您提到了使用 postgresql 的 application.properties,但是:我们如何将 application.properties 与 H2DB 一起使用?
      • 如果不设置属性,应用将默认使用H2DB
      猜你喜欢
      • 2020-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 2016-08-15
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多