简体   繁体   English

Spring 引导数据 r2dbc 自动创建表

[英]Spring boot data r2dbc auto create tables

I have a simple question, is it possible to auto-generate tables using spring boot data r2dbc for MySQL or other databases?我有一个简单的问题,是否可以使用 spring 引导数据 r2dbc 为 MySQL 或其他数据库自动生成表? in JPA I added spring.jpa.hibernate.ddl-auto=update and created tables在 JPA 我添加了 spring.jpa.hibernate.ddl-auto=update 并创建了表

This is my pom:这是我的 pom:

    <dependencies>
    <dependency>
        <groupId>org.springframework.boot.experimental</groupId>
        <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>dev.miku</groupId>
        <artifactId>r2dbc-mysql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot.experimental</groupId>
        <artifactId>spring-boot-test-autoconfigure-r2dbc</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.43.Final</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

I know that this is not the exact answer but the only way to create tables in R2DBC is to utilize databasePopulator :我知道这不是确切的答案,但在 R2DBC 中创建表的唯一方法是利用databasePopulator

@Bean
fun initializer(connectionFactory: ConnectionFactory) =
    ConnectionFactoryInitializer().apply {
        setConnectionFactory(connectionFactory)
        setDatabasePopulator(CompositeDatabasePopulator()
            .apply {
                addPopulators(ResourceDatabasePopulator(FileSystemResource("src/test/resources/sql/init.sql")))
            })
    }

It can come in handy during tests.它可以在测试期间派上用场。

In order for r2dbc to auto create tables on app startup all you need is a config java class annotated with the @Configuration eg:为了让 r2dbc 在应用程序启动时自动创建表,您只需要一个带有 @Configuration 注释的配置 java class 例如:

import io.r2dbc.spi.ConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;

@Configuration
public class DbSchemaInitOnStartup {

    @Bean
    ConnectionFactoryInitializer initializer(@Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
        ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
        initializer.setConnectionFactory(connectionFactory);
        ResourceDatabasePopulator resource = new ResourceDatabasePopulator(new ClassPathResource("schema.sql"));
        initializer.setDatabasePopulator(resource);
        return initializer;
    }

}

The schema.sql file must be placed in /resources folder for above to work. schema.sql文件必须放在/resources文件夹中才能正常工作。

For testing purpose, I tried this scenario by creating two datasources that point to the same database.出于测试目的,我通过创建两个指向同一数据库的数据源来尝试这种情况。 One is for JDBC and the other one is for R2DBC.一个用于 JDBC,另一个用于 R2DBC。

JDBC Datasource JDBC 数据源

@Configuration
@EnableJpaRepositories( basePackages = "com.ns.reactivetest.repository.jdbc", entityManagerFactoryRef = "jdbcEntityManager", transactionManagerRef = "jdbcTransactionManager" )
@EnableTransactionManagement
public class JdbcConfiguration {

    @Autowired
    Environment env;

    @Bean( name = "jdbcDataSource" )
    @Primary
    public DataSource jdbcDataSource( ) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource( );
        dataSource.setUrl( env.getProperty( "spring.datasource.url" ) );
        dataSource.setUsername( env.getProperty( "spring.datasource.username" ) );
        dataSource.setPassword( env.getProperty( "spring.datasource.password" ) );

        HikariDataSource hikariDataSource = new HikariDataSource( );
        hikariDataSource.setDataSource( dataSource );
        hikariDataSource.setMinimumIdle( Integer.valueOf( env.getProperty( "spring.datasource.hikari.minimum-idle" ) ) );
        hikariDataSource.setMaximumPoolSize( Integer.valueOf( env.getProperty( "spring.datasource.hikari.maximum-pool-size" ) ) );
        hikariDataSource.setSchema( env.getProperty( "spring.datasource.hikari.schema" ) );

        return hikariDataSource;
    }

    @Bean( name = "jdbcEntityManager" )
    @Primary
    public LocalContainerEntityManagerFactoryBean jdbcEntityManager( @Qualifier( "jdbcDataSource" ) DataSource dataSource ) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean( );
        em.setDataSource( dataSource );
        em.setPackagesToScan( new String[]{ "com.ns.reactivetest.domain" } );
        em.setPersistenceUnitName( "jdbc_persistence_Unit_Name" );

        JpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter( );
        em.setJpaVendorAdapter( jpaVendorAdapter );

        Properties properties = new Properties( );
        properties.setProperty( "hibernate.hbm2ddl.auto", env.getProperty( "spring.jpa.hibernate.ddl-auto" ) );
        properties.setProperty( "hibernate.dialect", env.getProperty( "spring.jpa.properties.hibernate.dialect" ) );
        em.setJpaProperties( properties );

        return em;
    }

    @Bean( name = "jdbcTransactionManager" )
    @Primary
    public PlatformTransactionManager jdbcTransactionManager( @Qualifier( "jdbcDataSource" ) DataSource dataSource ) {
        JpaTransactionManager transactionManager = new JpaTransactionManager( );
        transactionManager.setDataSource( dataSource );
        transactionManager.setPersistenceUnitName( "jdbc_persistence_Unit_Name" );
        return transactionManager;
    }

}

R2DBC Datasource R2DBC 数据源

@Configuration
@EnableR2dbcRepositories( basePackages = "com.ns.reactivetest.repository.reactive" )
@EnableTransactionManagement
public class R2DbcConfiguration  {

    @Autowired
    private Environment env;


    @Bean
    public ConnectionFactory connectionFactory( ) {
        ConnectionFactory connectionFactory = new PostgresqlConnectionFactory(
                PostgresqlConnectionConfiguration.builder( )
                        .host( env.getProperty( "spring.r2dbc.properties.hostname", "localhost" ) )
                        .database( env.getProperty( "spring.r2dbc.name", "postgres" ) )
                        .username( env.getProperty( "spring.r2dbc.username", "postgres" ) )
                        .password( env.getProperty( "spring.r2dbc.password", "password" ) )
                        .schema( env.getProperty( "spring.r2dbc.properties.schema", "public" ) )
                        .port( Integer.valueOf( env.getProperty( "spring.r2dbc.properties.port", "5432" ) ) )
                        //.options( options )
                        .build( )
        );
        if ( env.getProperty( "spring.r2dbc.pool.enabled", Boolean.class, false ) ) {
            ConnectionPoolConfiguration connectionPoolConfiguration = ConnectionPoolConfiguration.builder( connectionFactory )
                    .maxIdleTime( Duration.ofSeconds( env.getProperty( "spring.r2dbc.pool.max-idle-time", Long.class, 1800L ) ) ) // 30 Minutes
                    .initialSize( env.getProperty( "spring.r2dbc.pool.initial-size", Integer.class, 10 ) )
                    .maxSize( env.getProperty( "spring.r2dbc.pool.max-size", Integer.class, 25 ) )
                    .validationQuery( env.getProperty( "spring.r2dbc.validation-query", String.class, "SELECT 1" ) )
                    .build( );
            return new ConnectionPool( connectionPoolConfiguration );
        } else {
            return connectionFactory;
        }
    }

    @Bean
    ReactiveTransactionManager transactionManager( ConnectionFactory connectionFactory ) {
        return new R2dbcTransactionManager( connectionFactory );
    }

}

Note: Here I have used two pacakges for JDBC and R2DBC Repositoties.注意:这里我为 JDBC 和 R2DBC Repositoties 使用了两个包。

So far it is working fine.到目前为止它工作正常。 But I don't know how will this work for the complex scenarios and requirements.但我不知道这将如何适用于复杂的场景和要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM