spring data r2dbc 可以生成模式吗?
Can spring data r2dbc generate a schema?
我正在使用 R2DBC 和 H2 创建一个快速项目,以熟悉这种新的响应式内容。制作了一个扩展 ReactiveCrudRepository 的存储库,只要我使用 DatabaseClient 发出一个 CREATE TABLE 语句首先匹配我的实体...
我了解 spring 数据 R2DBC 的功能不如 spring 数据 JPA(还没有?),但目前是否有从实体 类 生成模式的方法?
谢谢
不,目前无法从具有 Spring 数据 R2DBC 的实体生成模式。
我在一个带有 Postgres DB 的项目中使用它,管理数据库迁移很复杂,但我设法在启动时使用同步 Postgre 驱动程序连接 Flyway(Flyway 还不能使用反应式驱动程序)来处理架构迁移。
即使您仍然必须编写自己的 CREATE TABLE 语句,这不应该那么难,您甚至可以在一些简单的项目中修改您的实体以创建 JPA 实体并让 Hibernate 创建模式然后复制- 将其粘贴到 R2DBC 项目的迁移文件中。
测试和生产都是可能的。
I production 请确保您的用户无权更改架构,否则您可能会误删表!!!或者使用 flyway 之类的迁移工具。
您需要将您的schema.sql放在主要资源中并添加相关属性
spring.r2dbc.initialization-mode=always
h2 用于测试,postgres 用于产品
我用的是gradle,驱动版本是:
implementation 'org.springframework.boot.experimental:spring-boot-actuator-autoconfigure-r2dbc'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'io.r2dbc:r2dbc-h2'
runtimeOnly 'io.r2dbc:r2dbc-postgresql'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot.experimental:spring-boot-test-autoconfigure-r2dbc'
BOM版本为
dependencyManagement {
imports {
mavenBom 'org.springframework.boot.experimental:spring-boot-bom-r2dbc:0.1.0.M3'
}
}
我就是这样解决这个问题的:
控制器:
@PostMapping(MAP + PATH_DDL_PROC_DB) //PATH_DDL_PROC_DB = "/database/{db}/{schema}/{table}"
public Flux<Object> createDbByDb(
@PathVariable("db") String db,
@PathVariable("schema") String schema,
@PathVariable("table") String table) {
return ddlProcService.createDbByDb(db,schema,table);
服务:
public Flux<Object> createDbByDb(String db,String schema,String table) {
return ddl.createDbByDb(db,schema,table);
}
存储库:
@Autowired
PostgresqlConnectionConfiguration.Builder connConfig;
public Flux<Object> createDbByDb(String db,String schema,String table) {
return createDb(db).thenMany(
Mono.from(connFactory(connConfig.database(db)).create())
.flatMapMany(
connection ->
Flux.from(connection
.createBatch()
.add(sqlCreateSchema(db))
.add(sqlCreateTable(db,table))
.add(sqlPopulateTable(db,table))
.execute()
)));
}
private Mono<Void> createDb(String db) {
PostgresqlConnectionFactory
connectionFactory = connFactory(connConfig);
DatabaseClient ddl = DatabaseClient.create(connectionFactory);
return ddl
.execute(sqlCreateDb(db))
.then();
}
连接Class:
@Slf4j
@Configuration
@EnableR2dbcRepositories
public class Connection extends AbstractR2dbcConfiguration {
/*
**********************************************
* Spring Data JDBC:
* DDL: does not support JPA.
*
* R2DBC
* DDL:
* -does no support JPA
* -To achieve DDL, uses R2dbc.DataBaseClient
*
* DML:
* -it uses R2dbcREpositories
* -R2dbcRepositories is different than
* R2dbc.DataBaseClient
* ********************************************
*/
@Bean
public PostgresqlConnectionConfiguration.Builder connectionConfig() {
return PostgresqlConnectionConfiguration
.builder()
.host("db-r2dbc")
.port(5432)
.username("root")
.password("root");
}
@Bean
public PostgresqlConnectionFactory connectionFactory() {
return
new PostgresqlConnectionFactory(
connectionConfig().build()
);
}
}
DDL 脚本:
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DDLScripts {
public static final String SQL_GET_TASK = "select * from tasks";
public static String sqlCreateDb(String db) {
String sql = "create database %1$s;";
String[] sql1OrderedParams = quotify(new String[]{db});
String finalSql = format(sql,(Object[]) sql1OrderedParams);
return finalSql;
}
public static String sqlCreateSchema(String schema) {
String sql = "create schema if not exists %1$s;";
String[] sql1OrderedParams = quotify(new String[]{schema});
return format(sql,(Object[]) sql1OrderedParams);
}
public static String sqlCreateTable(String schema,String table) {
String sql1 = "create table %1$s.%2$s " +
"(id serial not null constraint tasks_pk primary key, " +
"lastname varchar not null); ";
String[] sql1OrderedParams = quotify(new String[]{schema,table});
String sql1Final = format(sql1,(Object[]) sql1OrderedParams);
String sql2 = "alter table %1$s.%2$s owner to root; ";
String[] sql2OrderedParams = quotify(new String[]{schema,table});
String sql2Final = format(sql2,(Object[]) sql2OrderedParams);
return sql1Final + sql2Final;
}
public static String sqlPopulateTable(String schema,String table) {
String sql = "insert into %1$s.%2$s values (1, 'schema-table-%3$s');";
String[] sql1OrderedParams = quotify(new String[]{schema,table,schema});
return format(sql,(Object[]) sql1OrderedParams);
}
private static String[] quotify(String[] stringArray) {
String[] returnArray = new String[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
returnArray[i] = "\"" + stringArray[i] + "\"";
}
return returnArray;
}
}
实际上可以通过以这种方式定义特定的 class 来加载架构:
import io.r2dbc.spi.ConnectionFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
@Configuration
@EnableR2dbcRepositories
class DbConfig {
@Bean
fun initializer(connectionFactory: ConnectionFactory): ConnectionFactoryInitializer {
val initializer = ConnectionFactoryInitializer()
initializer.setConnectionFactory(connectionFactory)
initializer.setDatabasePopulator(
ResourceDatabasePopulator(
ClassPathResource("schema.sql")
)
)
return initializer
}
}
注意 IntelliJ 给出了一个错误“Could not autowire.No beans of 'ConnectionFactory' type found”,但它实际上是一个误报。所以忽略它并重新构建你的项目。
schema.sql
文件必须放在资源文件夹中。
我正在使用 R2DBC 和 H2 创建一个快速项目,以熟悉这种新的响应式内容。制作了一个扩展 ReactiveCrudRepository 的存储库,只要我使用 DatabaseClient 发出一个 CREATE TABLE 语句首先匹配我的实体...
我了解 spring 数据 R2DBC 的功能不如 spring 数据 JPA(还没有?),但目前是否有从实体 类 生成模式的方法?
谢谢
不,目前无法从具有 Spring 数据 R2DBC 的实体生成模式。
我在一个带有 Postgres DB 的项目中使用它,管理数据库迁移很复杂,但我设法在启动时使用同步 Postgre 驱动程序连接 Flyway(Flyway 还不能使用反应式驱动程序)来处理架构迁移。
即使您仍然必须编写自己的 CREATE TABLE 语句,这不应该那么难,您甚至可以在一些简单的项目中修改您的实体以创建 JPA 实体并让 Hibernate 创建模式然后复制- 将其粘贴到 R2DBC 项目的迁移文件中。
测试和生产都是可能的。
I production 请确保您的用户无权更改架构,否则您可能会误删表!!!或者使用 flyway 之类的迁移工具。
您需要将您的schema.sql放在主要资源中并添加相关属性
spring.r2dbc.initialization-mode=always
h2 用于测试,postgres 用于产品
我用的是gradle,驱动版本是:
implementation 'org.springframework.boot.experimental:spring-boot-actuator-autoconfigure-r2dbc'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'io.r2dbc:r2dbc-h2'
runtimeOnly 'io.r2dbc:r2dbc-postgresql'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot.experimental:spring-boot-test-autoconfigure-r2dbc'
BOM版本为
dependencyManagement {
imports {
mavenBom 'org.springframework.boot.experimental:spring-boot-bom-r2dbc:0.1.0.M3'
}
}
我就是这样解决这个问题的:
控制器:
@PostMapping(MAP + PATH_DDL_PROC_DB) //PATH_DDL_PROC_DB = "/database/{db}/{schema}/{table}"
public Flux<Object> createDbByDb(
@PathVariable("db") String db,
@PathVariable("schema") String schema,
@PathVariable("table") String table) {
return ddlProcService.createDbByDb(db,schema,table);
服务:
public Flux<Object> createDbByDb(String db,String schema,String table) {
return ddl.createDbByDb(db,schema,table);
}
存储库:
@Autowired
PostgresqlConnectionConfiguration.Builder connConfig;
public Flux<Object> createDbByDb(String db,String schema,String table) {
return createDb(db).thenMany(
Mono.from(connFactory(connConfig.database(db)).create())
.flatMapMany(
connection ->
Flux.from(connection
.createBatch()
.add(sqlCreateSchema(db))
.add(sqlCreateTable(db,table))
.add(sqlPopulateTable(db,table))
.execute()
)));
}
private Mono<Void> createDb(String db) {
PostgresqlConnectionFactory
connectionFactory = connFactory(connConfig);
DatabaseClient ddl = DatabaseClient.create(connectionFactory);
return ddl
.execute(sqlCreateDb(db))
.then();
}
连接Class:
@Slf4j
@Configuration
@EnableR2dbcRepositories
public class Connection extends AbstractR2dbcConfiguration {
/*
**********************************************
* Spring Data JDBC:
* DDL: does not support JPA.
*
* R2DBC
* DDL:
* -does no support JPA
* -To achieve DDL, uses R2dbc.DataBaseClient
*
* DML:
* -it uses R2dbcREpositories
* -R2dbcRepositories is different than
* R2dbc.DataBaseClient
* ********************************************
*/
@Bean
public PostgresqlConnectionConfiguration.Builder connectionConfig() {
return PostgresqlConnectionConfiguration
.builder()
.host("db-r2dbc")
.port(5432)
.username("root")
.password("root");
}
@Bean
public PostgresqlConnectionFactory connectionFactory() {
return
new PostgresqlConnectionFactory(
connectionConfig().build()
);
}
}
DDL 脚本:
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DDLScripts {
public static final String SQL_GET_TASK = "select * from tasks";
public static String sqlCreateDb(String db) {
String sql = "create database %1$s;";
String[] sql1OrderedParams = quotify(new String[]{db});
String finalSql = format(sql,(Object[]) sql1OrderedParams);
return finalSql;
}
public static String sqlCreateSchema(String schema) {
String sql = "create schema if not exists %1$s;";
String[] sql1OrderedParams = quotify(new String[]{schema});
return format(sql,(Object[]) sql1OrderedParams);
}
public static String sqlCreateTable(String schema,String table) {
String sql1 = "create table %1$s.%2$s " +
"(id serial not null constraint tasks_pk primary key, " +
"lastname varchar not null); ";
String[] sql1OrderedParams = quotify(new String[]{schema,table});
String sql1Final = format(sql1,(Object[]) sql1OrderedParams);
String sql2 = "alter table %1$s.%2$s owner to root; ";
String[] sql2OrderedParams = quotify(new String[]{schema,table});
String sql2Final = format(sql2,(Object[]) sql2OrderedParams);
return sql1Final + sql2Final;
}
public static String sqlPopulateTable(String schema,String table) {
String sql = "insert into %1$s.%2$s values (1, 'schema-table-%3$s');";
String[] sql1OrderedParams = quotify(new String[]{schema,table,schema});
return format(sql,(Object[]) sql1OrderedParams);
}
private static String[] quotify(String[] stringArray) {
String[] returnArray = new String[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
returnArray[i] = "\"" + stringArray[i] + "\"";
}
return returnArray;
}
}
实际上可以通过以这种方式定义特定的 class 来加载架构:
import io.r2dbc.spi.ConnectionFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
@Configuration
@EnableR2dbcRepositories
class DbConfig {
@Bean
fun initializer(connectionFactory: ConnectionFactory): ConnectionFactoryInitializer {
val initializer = ConnectionFactoryInitializer()
initializer.setConnectionFactory(connectionFactory)
initializer.setDatabasePopulator(
ResourceDatabasePopulator(
ClassPathResource("schema.sql")
)
)
return initializer
}
}
注意 IntelliJ 给出了一个错误“Could not autowire.No beans of 'ConnectionFactory' type found”,但它实际上是一个误报。所以忽略它并重新构建你的项目。
schema.sql
文件必须放在资源文件夹中。