Spring boot + Mybatis | 多数据源 | 自动建表

根据 Spring boot官方文档,Spring JPA / Hibernate 框架均可以在启动时自动建表

Spring Boot can automatically create the schema (DDL scripts) of your DataSource and initialize it (DML scripts). It loads SQL from the standard root classpath locations: schema.sql and data.sql, respectively. In addition, Spring Boot processes the schema-${platform}.sql and data-${platform}.sql files (if present), where platform is the value of spring.datasource.platform. This allows you to switch to database-specific scripts if necessary. For example, you might choose to set it to the vendor name of the database (hsqldb, h2, oracle, mysql, postgresql, and so on).

Spring Boot automatically creates the schema of an embedded DataSource. This behavior can be customized by using the spring.datasource.initialization-mode property. For instance, if you want to always initialize the DataSource regardless of its type:

spring.datasource.initialization-mode=always

Reference:Spring boot doc

而对于Spring boot本身,虽然按文档所说也可以自动建表,但

  • 不能指定schema文件位置(博主在使用datasource.schema属性指定schema文件具体位置时数据库表未成功创建)
  • 对多数据源并不友好(博主在多数据源场景下同时使用datasource.schema和datasource.initialization-mode配置时数据库表未成功创建)

为解决每次都需要手动创建数据表的痛点,在此贴出自己的解决方案,具体思路如下:

  • 手动读取schema-{platform}.sql文件
  • 手动执行建表语句

为使我们的建表语句能每次在程序启动时执行,博主这里使用了@EvenListener。

@Component
public class ApplicationInitializationConfig {
    @Autowired
    private ConfigurableApplicationContext ctx; \\ 用于在建表失败时退出

    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        initSchema(mysqlDataSource, mysqlSchemaResource);
        initSchema(h2DataSource, h2SchemaResource);
        ...
    }
}

接着编写用于读取和执行sql的函数

public void initSchema(DataSource dataSource, Resource resource) {
    try (Scanner scanner = new Scanner(resource.getFile());
         Connection connection = dataSource.getConnection()) {
        scanner.useDelimiter(";"); \\ schema.sql中使用;分隔各个建表语句
        while (scanner.hasNext())
            connection.prepareStatement(scanner.next()).execute();
    } catch (IOException | SQLException e) {
        e.printStackTrace();
        ctx.close(); \\ 失败则退出
    }
}

再通过application.yml配置schema.sql文件位置

spring:
  datasource:
    mysql:
      db-schema: schema-mysql.sql
    h2:
      db-schema: schema-h2.sql

注:这里不用mysql.schema是为了和datasource本身的schema属性加以区分
最后完成配置属性的注入就大功告成了

@Component
public class ApplicationInitializationConfig {
    @Autowired
    private ConfigurableApplicationContext ctx;
    @Autowired
    @Qualifier("mysqlDataSource")
    private DataSource mysqlDataSource;
    @Autowired
    @Qualifier("h2DataSource")
    private DataSource h2DataSource;

    @Value("${spring.datasource.h2.db-schema}")
    private Resource h2SchemaResource;
    @Value("${spring.datasource.mysql.db-schema}")
    private Resource mysqlSchemaResource;

    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        initSchema(persistentDataSource, persistentSchemaResource);
        initSchema(h2DataSource, h2SchemaResource);
    }

    public void initSchema(DataSource dataSource, Resource resource) {
        try (Scanner scanner = new Scanner(resource.getFile());
             Connection connection = dataSource.getConnection()) {
            scanner.useDelimiter(";");
            while (scanner.hasNext())
                connection.prepareStatement(scanner.next()).execute();
        } catch (IOException | SQLException e) {
            e.printStackTrace();
            ctx.close();
        }
    }
}

你可能感兴趣的:(Spring boot + Mybatis | 多数据源 | 自动建表)