文章目录
- 前言
 - 多数据源 使用 flyWay 进行数据库管理
 - 1. 环境
 - 2. flyway版本 与 MySQL 版本 对应关系
 - 3. flyway 脚本文件命名方式
 - 4. flyway工作流程
 - 5. 知识点补充
 - 6. 集成的时候常见错误
 - 6.1. user_variables_by_thread没有访问权限
 - 6.2. MySQL不支持Flyway社区版,只支持Flyway企业版
 - 6.3. SQL注入违规
 
- 7. Flyway 集成 SpringBoot 实战
 - 7.1. 依赖
 - 7.2. 配置
 - 7.3. Flyway 测试脚本
 - 7.4. 测试
 
前言
  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
   而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!
多数据源 使用 flyWay 进行数据库管理
flyway是一个开源的数据库迁移工具,它能够自动管理SQL脚本的执行,从而使数据库版本控制和升级变得更加容易。它支持各种数据库(Oracle,MySQL,PostgreSQL,SQL Server等)和多种脚本语言(SQL,Java,Groovy等)。用户可以使用命令行或API将SQL脚本打包在项目中,然后在开发过程中对数据库进行管理和升级。flyway对于Web开发人员来说是非常有用的,它可以自动检测和执行需要执行的脚本。
1. 环境
mysql : 5.7
 springBoot 版本: 2.7.3
2. flyway版本 与 MySQL 版本 对应关系
- Flyway 6.x.x:支持MySQL 5.5及以上版本;
 - Flyway 7.x.x:支持MySQL 5.6及以上版本;
 - Flyway 8.x.x:支持MySQL 5.7及以上版本;
 - Flyway 8.2.x:支持MySQL 8.0及以上版本。
 
需要注意的是,Flyway对于不同版本的MySQL数据库,支持的功能也会有所不同。因此,在选择使用哪个版本的Flyway时,需要根据实际情况来进行选择。
3. flyway 脚本文件命名方式
| 序号 | 类型 | 内容 | 格式 | 备注 | 
|---|---|---|---|---|
| 1 | 版本迁移 | 以V开头,只会执行一次 | V{版本号(可以用点或下划线)}{分隔符(默认:__)}{描述}.sql | |
| 2 | 回退迁移 | 以U开头 | U{版本号(可以用点或下划线)}{分隔符(默认:__)}{描述}.sql | 执行一旦发生破坏性更改,会很麻烦,项目中一般不用。 | 
| 3 | 可重复执行迁移 | 以R开头 | R{分隔符(默认:__)}{描述}.sql | 
优先级:
 V开头的SQL执行优先级要比R开头的SQL 优先级高。
注意:
 对于V开头的SQL脚本,版本号需要唯一,否则Flyway执行会报错;R开头的SQL脚本,如有变化可以执行多次。
4. flyway工作流程
- 项目启动、数据库连接池建立、flyway 运行;
 - 初次使用时,如果不设置table值,flyway会默认创建一个 flyway_schema_history 表,用于记录sql执行记录;
 - 如果不配做扫描路径,Flyway会扫描项目 classpath:db/migration 下的所有sql脚本,与存储记录sql执行表里的记录做对比,当validate-on-migrate为true时,进行校验,比如对于V开头的SQL脚本,版本号需要唯一,否则Flyway执行会报错等等…,一旦发现问题,Flyway抛出异常并停止项目;
 - 校验通过,则根据表中的sql记录最大版本号,忽略所有版本号不大于该版本的脚本。再按照版本号从小到大,逐个执行其余脚本。
 
5. 知识点补充
- flyway执行migrate必须在空白的数据库上进行,否则报错;
 - 对于已经有数据的数据库,必须先baseline,然后才能migrate;
 - clean操作是删除数据库的所有内容,包括baseline之前的内容;
 - 尽量不要修改已经执行过的SQL,即便是R开头的可反复执行的SQL,它们会不利于数据迁移;
 - 当需要做数据迁移的时候,更换一个新的空白数据库,执行下migrate命令,所有的数据库更改都可以一步到位地迁移过去;
 
6. 集成的时候常见错误
6.1. user_variables_by_thread没有访问权限
Caused by: java.sql.SQLSyntaxErrorException: SELECT command denied to user ‘TESTTWO’@‘localhost’ for table ‘user_variables_by_thread’

 解决:
GRANT SELECT ON performance_schema.user_variables_by_thread TO 'TESTTWO'@'localhost';
GRANT SELECT ON performance_schema.user_variables_by_thread TO 'TESTONE'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
 
6.2. MySQL不支持Flyway社区版,只支持Flyway企业版
.FlywayEditionUpgradeRequiredException: Flyway Teams Edition or MySQL upgrade required: MySQL 5.7 is no longer supported by Flyway Community Edition, but still supported by Flyway Teams Edition.
 
 大致意思是:MySQL 5.7不支持Flyway社区版,只支持Flyway企业版,提出的解决方案是改成企业版或升级MySQL。
解决:
 降低Flyway版本性价比应该是最高的,最快速的。
6.3. SQL注入违规
sql injection violation, comment not allow :
 
 因为我这里用的多数据源有filter,把防注入去掉就好
 解决:
 把这里的wall 去掉。
 
7. Flyway 集成 SpringBoot 实战
7.1. 依赖
        <!--多数据源-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
                <!-- flyway -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>5.2.3</version>
        </dependency>
 
7.2. 配置
package org.example.config;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.io.File;
import java.util.Map;
/**
 * @author yangzhenyu
 * @version 1.0
 * @description:
 * @date 2023/5/5 13:36
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableTransactionManagement
public class FlywayConfig {
    private final DataSource dataSource;
    // 是否启用 Flyway,true 启用,false 不启用
    @Value("${spring.flyway.enabled: false}")
    private Boolean FLYWAY_ENABLED;
    // 指定 SQL 脚本文件夹路径 这里写主库路径,然后在配置类中转换
    @Value("${spring.flyway.locations: classpath:db/master}")
    private String SQL_LOCATION;
    // 版本更新历史记录表
    @Value("${spring.flyway.table: yzy_db_version}")
    private String VERSION_TABLE;
    // 是否可以无序执行
    @Value("${spring.flyway.out-of-order: false}")
    private Boolean OUT_OF_ORDER;
    // 迁移前校验 SQL 文件是否存在问题
    @Value("${spring.flyway.validate-on-migrate: true}")
    private Boolean VALIDATE_ON_MIGRATE;
    // 编码格式,默认UTF-8
    @Value("${spring.flyway.encoding: UTF-8}")
    private String ENCODING;
    // 迁移sql脚本文件名称的前缀,默认V
    @Value("${spring.flyway.sql-migration-prefix: V}")
    private String SQL_MIGRATION_PREFIX;
    //迁移sql脚本文件名称的分隔符,默认2个下划线__
    @Value("${spring.flyway.sql-migration-separator: __}")
    private String SQL_MIGRATION_SEPARATOR ;
    // 迁移sql脚本文件名称的后缀
    @Value("${spring.flyway.sql-migration-suffixes: .sql}")
    private String SQL_MIGRATION_SUFFIXES ;
    // 非空数据库初始化Flyway时需要打开此开关进行Baseline操作 (如果数据库不是空表,需要设置成 true,否则启动报错)
    @Value("${spring.flyway.baseline-on-migrate: true}")
    private Boolean BASELINE_ON_MIGRATE;
    // 基础版本号  与 baseline-on-migrate: true 搭配使用
    @Value("${spring.flyway.baseline-version: 1}")
    private String BASELINE_VERSION;
    @Primary
    @Bean
    @PostConstruct
    public void migrateOrder() {
        if (FLYWAY_ENABLED) {
            log.info("调用数据库生成工具");
            SQL_LOCATION = SQL_LOCATION.split("/")[0]; // 多数据源的配置
            DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
            Map<String, DataSource> dataSources = ds.getDataSources();
            dataSources.forEach((k, v) -> {
                log.info("正在执行多数据源生成数据库文件 " + k);
                Flyway flyway = Flyway.configure()
                        .dataSource(v)
                        .locations(SQL_LOCATION + File.separator + k)
                        .baselineOnMigrate(BASELINE_ON_MIGRATE)
                        .table(VERSION_TABLE)
                        .outOfOrder(OUT_OF_ORDER)
                        .validateOnMigrate(VALIDATE_ON_MIGRATE)
                        .encoding(ENCODING)
                        .sqlMigrationPrefix(SQL_MIGRATION_PREFIX)
                        .sqlMigrationSeparator(SQL_MIGRATION_SEPARATOR)
                        .sqlMigrationSuffixes(SQL_MIGRATION_SUFFIXES)
                        .baselineVersion(BASELINE_VERSION)
                        .load();
                flyway.migrate();
            });
        }
    }
}
 
spring:
  datasource:
    dynamic: # druid连接池配置
      primary: master #默认数据源
      datasource:
        master: #主库配置
          username: TESTONE
          password: TESTONE
          driver-class-name: ${datasource_driver_class_name:com.mysql.cj.jdbc.Driver}
          url: ${datasource_url:jdbc:mysql://localhost:3306/TESTONEDB?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true}
          druid:
            initial-size: 5 #启动程序时,在连接池中初始化多少个连接
            max-active: 20 #连接池中最多支持多少个活动会话
            min-idle: 5 #回收空闲连接时,将保证至少有minIdle个连接
            max-wait: 60000 #程序向连接池中请求连接时,超过maxWait的值后,认为本次请求失败,即连接池
            filters: stat,slf4j
        slave: #从库配置
          username: TESTTWO
          password: TESTTWO
          driver-class-name: ${datasource_driver_class_name:com.mysql.cj.jdbc.Driver}
          url: ${datasource_url:jdbc:mysql://localhost:3306/TESTTWODB?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true}
          druid:
            initial-size: 5 #启动程序时,在连接池中初始化多少个连接
            max-active: 20 #连接池中最多支持多少个活动会话
            min-idle: 5 #回收空闲连接时,将保证至少有minIdle个连接
            max-wait: 60000 #程序向连接池中请求连接时,超过maxWait的值后,认为本次请求失败,即连接池
            filters: stat,slf4j
  flyway:
    enabled: true # 是否启用 Flyway,true 启用,false 不启用
    # 版本更新历史记录表
    table: yzy_db_version
    # 非空数据库初始化Flyway时需要打开此开关进行Baseline操作
    baseline-on-migrate: true
    # 是否可以无序执行
    out-of-order: false
    # 迁移前校验 SQL 文件是否存在问题
    validate-on-migrate: false
    locations: classpath:db/master  # 指定 SQL 脚本文件夹路径 这里写主库路径,然后在配置类中转换
    # 编码格式,默认UTF-8
    encoding: UTF-8
    # 迁移sql脚本文件名称的前缀,默认V
    sql-migration-prefix: V
    # 迁移sql脚本文件名称的分隔符,默认2个下划线__
    sql-migration-separator: __
    # 迁移sql脚本文件名称的后缀
    sql-migration-suffixes: .sql
    # 基础版本号
    baseline-version: 1
 
7.3. Flyway 测试脚本

 V20230505_1__yzy_db_version_remark.sql
alter table yzy_db_version comment 'flyway数据库版本控制表';
 
V20230505_2__新增测试表.sql
create table flyway_test
(
    ID   int(18) auto_increment comment 'id'
        primary key,
    AGE  int(100)     not null comment '年龄',
    NAME varchar(100) null comment '姓名',
    CREATE_TIME    datetime null comment '删除时间'
)
 
7.4. 测试
项目启动,查看数据库信息:
 select * from yzy_db_version;

 
 
 
 说明集成成功!!!



















