文章目录
- 前言
- 多数据源 使用 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;
说明集成成功!!!