簡體   English   中英

使用 inMemory 數據庫時出現 R2dbc H2 問題

[英]R2dbc H2 issues when using inMemory database

我試圖品嘗 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()
        );
    }

我定義了一個 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初始化成功,並通過執行schema.sql 和data.sql 創建了表POSTS並按預期插入了數據。

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

完整的代碼在這里

來自官方文檔

連接工廠

@Configuration
public class ApplicationConfiguration extends AbstractR2dbcConfiguration {

  @Override
  @Bean
  public ConnectionFactory connectionFactory() {
    return …;
  }
}

這種方法允許您使用標准的 io.r2dbc.spi.ConnectionFactory 實例,容器使用 Spring 的 AbstractR2dbcConfiguration。 與直接注冊 ConnectionFactory 實例相比,配置支持還有一個額外的優勢,即還為容器提供了一個 ExceptionTranslator 實現,該實現將 R2DBC 異常轉換為 Spring 的可移植 DataAccessException 層次結構中的異常,用於使用 @Repository 注釋注釋的數據訪問類。

(……)

AbstractR2dbcConfiguration 還注冊了 DatabaseClient,這是數據庫交互和 Repository 實現所必需的。

我寫了一個博客張貼有關如何設置開始使用R2DBC開始在這里 是使用 H2 數據庫的示例

我的猜測是您沒有正確初始化連接工廠,因此沒有獲得正確的 DatabaseClient。

我從 Spring Data R2dc 開發人員@mp911de 那里得到了答案。 #issue269

該問題與 H2 在最后一個連接關閉時關閉數據庫的行為有關。 請配置 DB_CLOSE_DELAY=-1 選項,以便 H2 保留數據庫。 或者,使用 H2ConnextionFactory.inMemory(...) 工廠方法創建不依賴於使用中連接計數的 Closeable 連接工廠。

將我的代碼更改為以下內容,它有效:


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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM