Spring R2DBC 使用 postgres 初始化数据库的正确方法

Spring R2DBC proper way to initialize database with postgres

我有以下代码:

@Component
public class TemplateDatabaseLoader {
    private Logger LOGGER = LoggerFactory.getLogger(TemplateDatabaseLoader.class);

    @Bean
    public CommandLineRunner demo(DatabaseClient databaseClient, ItemRepository itemRepository) {
        return args -> {
            databaseClient.execute(
                    "CREATE TABLE item (" +
                            "id SERIAL PRIMARY KEY," +
                            "name VARCHAR(255)," +
                            "price REAL" +
                        ");"
            ).fetch().all().blockLast(Duration.ofSeconds(10));
            itemRepository.save(new Item("Alf alarm clock", 19.99)).block();
            LOGGER.debug("COMMAND LINE RUNNER");
            itemRepository.save(new Item("Smurf TV tray", 24.99)).block();
        };
    }
}

并且:

@SpringBootApplication
public class DemoApplication extends AbstractR2dbcConfiguration {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public ConnectionFactory connectionFactory() {
        PostgresqlConnectionFactory connectionFactory = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
                .host("127.0.0.1")
                .database("cart")
                .username("cart")
                .password("cart").build());
        return connectionFactory;
    }

    @Bean(name={"r2dbcDatabaseClient"})
    DatabaseClient databaseClient() {
        return DatabaseClient.create(connectionFactory());
    }
}

我收到以下错误:

Suppressed: java.lang.Exception: #block terminated with an error
Caused by: io.r2dbc.postgresql.ExceptionFactory$PostgresqlBadGrammarException: relation "item" already exists

以及之前的错误:

Caused by: java.lang.ClassNotFoundException: org.springframework.jdbc.CannotGetJdbcConnectionException

如果我修改我的代码说:

CREATE TABLE IF NOT EXISTS item

然后我不再收到关于存在的项目关系的错误,但是,交易似乎被完全取消了?

我得到以下输出:

2020-09-21 17:31:58.476 DEBUG 16639 --- [  restartedMain] com.example.demo.TemplateDatabaseLoader  : COMMAND LINE RUNNER
2020-09-21 17:31:58.476 DEBUG 16639 --- [actor-tcp-nio-2] i.r.postgresql.util.FluxDiscardOnCancel  : received cancel signal

所以我的问题是

  1. 正确的做法是什么?

  2. 为什么我的 CommandLineRunner 代码似乎执行了两次? table 在 运行 代码之后不会持续存在,所以它似乎必须执行两次才能得到关于 table existing.

    的第一个错误

谢谢。

我成功了。我添加了一个新的 class 以从文件加载模式:

@Configuration
public class InitializerConfiguration {
    private Logger LOGGER = LoggerFactory.getLogger(InitializerConfiguration.class);

    @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")));
        initializer.setDatabasePopulator(populator);

        return initializer;
    }
}

这会加载资源下的 schema.sql。我的 TemplateDatabaseLoader 现在看起来像这样:

@Component
public class TemplateDatabaseLoader {
    private Logger LOGGER = LoggerFactory.getLogger(TemplateDatabaseLoader.class);

    @Bean
    public CommandLineRunner demo(ItemRepository itemRepository) {
        return args -> {
            itemRepository.save(new Item("Alf alarm clock", 19.99)).block();
            itemRepository.save(new Item("Smurf TV tray", 24.99)).block();
        };
    }
}

这会加载两个项目。