参考文献

背景说明

  • 由于公司架构升级,需要把部分组件抽离出来重构,需要抽离出一个所有组件的父组件项目来统一管理其他组件公共的功能模块或者依赖等.父组件项目由于有些配置项需要灵活配置,故而将这些配置项放入数据库表中进行管理.所以这边采用Flyway框架来管理这些SQL.
  • 但由于父组件和子组件都需要使用Flyway框架,因此对此进行调查研究一下.

环境说明

  • 父子项目A和B,A为父项目,B为子项目.

  • 父子项目都为SpringBoot项目.

  • JDK版本为11

  • SpringBoot版本如下所示:

    1
    2
    3
    4
    5
    6
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
    <relativePath/> <!-- lookup parent from repository -->
    </parent>
  • Flyway版本如下所示:

    1
    2
    3
    4
    5
    6
    <!-- flyway.version为8.0.2-->
    <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>${flyway.version}</version>
    </dependency>
  • 数据库采用MySQL 8.0

  • 父项目测试脚本文件名为BASE_1.0.0.0__INIT_TABLE.sql,其本身没有内容.

  • 子项目测试脚本文件名为DICOM_1.0.0.0__CREATE_DICOM_TAG_TABLE.sql,其内容如下(即会创建一张名为dicom_tag的表)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DROP TABLE
    IF
    EXISTS `dicom_tag`;
    CREATE TABLE `dicom_tag` (
    `id` INT auto_increment NOT NULL,
    `flag` VARCHAR ( 100 ) NOT NULL COMMENT 'Tag标识',
    `coordinates` CHAR ( 11 ) NOT NULL COMMENT 'Tag标准坐标',
    `tag_value` int NOT NULL COMMENT '程序对应的Tag值',
    `need_check` TINYINT NOT NULL DEFAULT 0 COMMENT '是否需要校验,0-无需校验;1-需要校验',
    `value_type` VARCHAR ( 50 ) NOT NULL COMMENT 'Tag值的数据类型',
    `description` text NULL COMMENT 'Tag描述',
    PRIMARY KEY ( `id` ),
    UNIQUE KEY ( `flag` )
    );

配置说明

  • 父子项目同时使用Flyway,父项目需要手动配置Flyway Bean以及配置Flyway迁移策略,子项目需要手动配

    Flyway Bean

  • 父项目Flyway Bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package cn.holelin.flywaybase.config;

    import org.flywaydb.core.Flyway;
    import org.flywaydb.core.api.configuration.FluentConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    /**
    * @Description: 基础Flyway配置类
    * @Author: HoleLin
    * @CreateDate: 2022/5/3 6:28 PM
    * @UpdateUser: HoleLin
    * @UpdateDate: 2022/5/3 6:28 PM
    * @UpdateRemark: 修改内容
    * @Version: 1.0
    */
    @Configuration
    public class FlywayBaseMigrationConfig {

    @Bean
    public FluentConfiguration moduleBaseFlywayMigrationConfig() {
    return Flyway.configure()
    .sqlMigrationPrefix("BASE_")
    .table("flyway_base_schema_history")
    .locations("db/migration/base");
    }
    }

  • 配置Flyway迁移策略

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package cn.holelin.flywaybase.config;

    import org.flywaydb.core.Flyway;
    import org.flywaydb.core.api.configuration.FluentConfiguration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
    import org.springframework.stereotype.Component;

    import java.util.List;

    /**
    * @Description: 基础Flyway迁移策略
    * @Author: HoleLin
    * @CreateDate: 2022/5/3 6:28 PM
    * @UpdateUser: HoleLin
    * @UpdateDate: 2022/5/3 6:28 PM
    * @UpdateRemark: 修改内容
    * @Version: 1.0
    */
    @Component
    public class FlywayBaseMigrationStrategy implements FlywayMigrationStrategy {

    @Autowired
    private List<FluentConfiguration> migrations;

    @Override
    public void migrate(Flyway flyway) {
    this.migrations.forEach(mig -> mig.
    baselineOnMigrate(true).
    baselineVersion("0").
    dataSource(flyway.getConfiguration().getDataSource()).
    load().
    migrate())
    }
    }

  • 子项目Flyway Bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package cn.holelin.dicom.config;

    import org.flywaydb.core.Flyway;
    import org.flywaydb.core.api.configuration.FluentConfiguration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    /**
    * @Description: 子项目Flyway配置类
    * @Author: HoleLin
    * @CreateDate: 2022/5/3 6:28 PM
    * @UpdateUser: HoleLin
    * @UpdateDate: 2022/5/3 6:28 PM
    * @UpdateRemark: 修改内容
    * @Version: 1.0
    */
    @Configuration
    public class FlywayMigrationConfig {

    @Autowired
    private FlywayProperties flywayProperties;
    @Bean
    public FluentConfiguration moduleFlywayMigrationConfig() {
    return Flyway.configure()
    .sqlMigrationPrefix(flywayProperties.getSqlMigrationPrefix())
    .table(flywayProperties.getTable())
    .locations(String.join(",",flywayProperties.getLocations()));
    }
    }
  • 若不在父项目中配置Flyway Bean以及Flyway迁移策略的话,会导致父项目在被子项目继承或者引用时,启动子项目后,只有子项目中被Flyway管理的脚本被执行,父项目的Flyway所管理的脚本无法被执行.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    2022-05-04 01:03:14.921  INFO 19283 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 8.0.2 by Redgate
    2022-05-04 01:03:14.921 INFO 19283 --- [ main] o.f.c.i.database.base.BaseDatabaseType : Database: jdbc:mysql://localhost:3306/dicom (MySQL 8.0)
    2022-05-04 01:03:14.947 INFO 19283 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.011s)
    2022-05-04 01:03:14.964 INFO 19283 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `dicom`.`flyway_schema_history` ...
    2022-05-04 01:03:15.010 INFO 19283 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `dicom`: << Empty Schema >>
    2022-05-04 01:03:15.014 INFO 19283 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `dicom` to version "1.0.0.0 - CREATE DICOM TAG TABLE"
    2022-05-04 01:03:15.022 WARN 19283 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Unknown table 'dicom.dicom_tag' (SQL State: 42S02 - Error Code: 1051)
    2022-05-04 01:03:15.038 INFO 19283 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `dicom`, now at version v1.0.0.0 (execution time 00:00.030s)
    2022-05-04 01:03:15.090 INFO 19283 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
    2022-05-04 01:03:15.096 INFO 19283 --- [ main] cn.holelin.dicom.DicomApplication : Started DicomApplication in 1.213 seconds (JVM running for 1.715)
    • 由上述打印的日志,可以发现只有子项目的脚本被执行了.
  • 若只在父项目中配置Flyway Bean以及Flyway迁移策略,子项目不配置Flyway Bean则会导致,只有父项目的脚本被执行.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    2022-05-04 00:58:58.380  INFO 19118 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 8.0.2 by Redgate
    2022-05-04 00:58:58.380 INFO 19118 --- [ main] o.f.c.i.database.base.BaseDatabaseType : Database: jdbc:mysql://localhost:3306/dicom (MySQL 8.0)
    2022-05-04 00:58:58.403 INFO 19118 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.006s)
    2022-05-04 00:58:58.415 INFO 19118 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `dicom`.`flyway_base_schema_history` ...
    2022-05-04 00:58:58.454 INFO 19118 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `dicom`: << Empty Schema >>
    2022-05-04 00:58:58.457 INFO 19118 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `dicom` to version "1.0.0.0 - INIT TABLE"
    2022-05-04 00:58:58.467 INFO 19118 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `dicom`, now at version v1.0.0.0 (execution time 00:00.015s)
    2022-05-04 00:58:58.519 INFO 19118 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
    2022-05-04 00:58:58.526 INFO 19118 --- [ main] cn.holelin.dicom.DicomApplication : Started DicomApplication in 1.091 seconds (JVM running for 1.449)
    • 由上述日志中,可以发现Flyway成功迁移了父项目的1.0.0.0 - INIT TABLE脚本,但是子项目的脚本为成功执行.
  • 父子项目都配置完毕后,其输出的日志,数据库中创建的表以及Flyway执行脚本记录表的内容如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    2022-05-04 01:16:56.035  INFO 20535 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 8.0.2 by Redgate
    2022-05-04 01:16:56.036 INFO 20535 --- [ main] o.f.c.i.database.base.BaseDatabaseType : Database: jdbc:mysql://localhost:3306/dicom (MySQL 8.0)
    2022-05-04 01:16:56.064 INFO 20535 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.016s)
    2022-05-04 01:16:56.086 INFO 20535 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `dicom`.`flyway_schema_history` ...
    2022-05-04 01:16:56.120 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `dicom`: << Empty Schema >>
    2022-05-04 01:16:56.124 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `dicom` to version "1.0.0.0 - CREATE DICOM TAG TABLE"
    2022-05-04 01:16:56.132 WARN 20535 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Unknown table 'dicom.dicom_tag' (SQL State: 42S02 - Error Code: 1051)
    2022-05-04 01:16:56.149 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `dicom`, now at version v1.0.0.0 (execution time 00:00.032s)
    2022-05-04 01:16:56.156 INFO 20535 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 8.0.2 by Redgate
    2022-05-04 01:16:56.156 INFO 20535 --- [ main] o.f.c.i.database.base.BaseDatabaseType : Database: jdbc:mysql://localhost:3306/dicom (MySQL 8.0)
    2022-05-04 01:16:56.163 INFO 20535 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.001s)
    2022-05-04 01:16:56.176 INFO 20535 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `dicom`.`flyway_base_schema_history` with baseline ...
    2022-05-04 01:16:56.192 INFO 20535 --- [ main] o.f.core.internal.command.DbBaseline : Successfully baselined schema with version: 0
    2022-05-04 01:16:56.194 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `dicom`: 0
    2022-05-04 01:16:56.196 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `dicom` to version "1.0.0.0 - INIT TABLE"
    2022-05-04 01:16:56.202 INFO 20535 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `dicom`, now at version v1.0.0.0 (execution time 00:00.009s)
    2022-05-04 01:16:56.245 INFO 20535 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
    2022-05-04 01:16:56.251 INFO 20535 --- [ main] cn.holelin.dicom.DicomApplication : Started DicomApplication in 1.23 seconds (JVM running for 1.631)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    mysql> show tables;
    +----------------------------+
    | Tables_in_dicom |
    +----------------------------+
    | dicom_tag |
    | flyway_base_schema_history |
    | flyway_schema_history |
    +----------------------------+
    3 rows in set (0.00 sec)

    mysql> select * from flyway_base_schema_history\G
    *************************** 1. row ***************************
    installed_rank: 1
    version: 0
    description: << Flyway Baseline >>
    type: BASELINE
    script: << Flyway Baseline >>
    checksum: NULL
    installed_by: root
    installed_on: 2022-05-04 01:16:56
    execution_time: 0
    success: 1
    *************************** 2. row ***************************
    installed_rank: 2
    version: 1.0.0.0
    description: INIT TABLE
    type: SQL
    script: BASE_1.0.0.0__INIT_TABLE.sql
    checksum: 0
    installed_by: root
    installed_on: 2022-05-04 01:16:56
    execution_time: 1
    success: 1
    2 rows in set (0.00 sec)

    mysql> select * from flyway_schema_history\G
    *************************** 1. row ***************************
    installed_rank: 1
    version: 1.0.0.0
    description: CREATE DICOM TAG TABLE
    type: SQL
    script: DICOM_1.0.0.0__CREATE_DICOM_TAG_TABLE.sql
    checksum: 115451493
    installed_by: root
    installed_on: 2022-05-04 01:16:56
    execution_time: 12
    success: 1
    1 row in set (0.00 sec)
  • TIPS: 父子项目创建的时,建议包名前缀保持一致.

示例

父项目

  • 其主要文件目录结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ├── pom.xml
    ├── src
    │   ├── main
    │   │   ├── java
    │   │   │   └── cn
    │   │   │   └── holelin
    │   │   │   └── flywaybase
    │   │   │   ├── FlywayBaseApplication.java
    │   │   │   └── config
    │   │   │   ├── FlywayBaseMigrationConfig.java
    │   │   │   └── FlywayBaseMigrationStrategy.java
    │   │   └── resources
    │   │   ├── application.yml
    │   │   └── db
    │   │   └── migration
    │   │   └── base
    │   │   └── BASE_1.0.0.0__INIT_TABLE.sql
  • FlywayBaseMigrationConfig类中内容即为手动定义的Flyway Bean,FlywayBaseMigrationStrategy即为迁移策略

子项目

  • 其主要文件目录结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ├── pom.xml
    ├── src
    │   ├── main
    │   │   ├── java
    │   │   │   └── cn
    │   │   │   └── holelin
    │   │   │   └── dicom
    │   │   │   ├── DicomApplication.java
    │   │   │   ├── config
    │   │   │   │   └── FlywayMigrationConfig.java
    │   │   └── resources
    │   │   ├── application.yml
    │   │   ├── db
    │   │   │   └── migration
    │   │   │   └── DICOM_1.0.0.0__CREATE_DICOM_TAG_TABLE.sql
  • FlywayMigrationConfig即为子项目的Flyway Bean

  • 其中DicomApplication中需要手动指定SpringBoot扫描Bean的包路径,保证父项目中创建的Bean被加入到Spring容器中,其代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package cn.holelin.dicom;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication(scanBasePackages="cn.holelin")
    public class DicomApplication {

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