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
所以我的问题是
正确的做法是什么?
为什么我的 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();
};
}
}
这会加载两个项目。
我有以下代码:
@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
所以我的问题是
正确的做法是什么?
为什么我的 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();
};
}
}
这会加载两个项目。