flyway数据库版本管理工具
Flyway是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations可以写成SQL脚本,也可以写在Java代码中,不仅支持Command Line和Java API,还支持Build构建工具和Spring Boot等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。
Flyway主要基于6种基本命令:Migrate, Clean, Info, Validate, Baseline and Repair,稍候会逐一分析讲解。目前支持的数据库主要有:Oracle, SQL Server, SQL Azure, DB2, DB2 z/OS, MySQL(including Amazon RDS), MariaDB, Google Cloud SQL, PostgreSQL(including Amazon RDS and Heroku), Redshift, Vertica, H2, Hsql, Derby, SQLite, SAP HANA, solidDB, Sybase ASE and Phoenix.
为什么使用Flyway?
通常在项目开始时会针对数据库进行全局设计,但在开发产品新特性过程中,难免会遇到需要更新数据库Schema的情况,比如:添加新表,添加新字段和约束等,这种情况在实际项目中也经常发生。那么,当开发人员完成了对数据库更的SQL脚本后,如何快速地在其他开发者机器上同步?并且如何在测试服务器上快速同步?以及如何保证集成测试能够顺利执行并通过呢?
其实,以上问题可以通过Flyway工具来解决,Flyway可以实现自动化的数据库版本管理,并且能够记录数据库版本更新记录
Flyway如何工作的?
Flyway对数据库进行版本管理主要由Metadata表和6种命令完成,Metadata主要用于记录元数据,每种命令功能和解决的问题范围不一样,以下分别对metadata表和这些命令进行阐述,其中的示意图都来自Flyway的官方文档。
Flyway中最核心的就是用于记录所有版本演化和状态的Metadata表,在Flyway首次启动时会创建默认名为schema_version的元数据表,记录每次更新的版本信息。
Migrate
Migrate是指把数据库Schema迁移到最新版本,是Flyway工作流的核心功能,Flyway在Migrate时会检查Metadata(元数据)表,如果不存在会创建Metadata表,Metadata表主要用于记录版本变更历史以及Checksum之类的。
Migrate时会扫描指定文件系统或Classpath下的Migrations(可以理解为数据库的版本脚本),并且会逐一比对Metadata表中的已存在的版本记录,如果有未应用的Migrations,Flyway会获取这些Migrations并按次序Apply到数据库中,否则不需要做任何事情。另外,通常在应用程序启动时应默认执行Migrate操作,从而避免程序和数据库的不一致性。
Clean
Clean相对比较容易理解,即清除掉对应数据库Schema中的所有对象,包括表结构,视图,存储过程,函数以及所有的数据等都会被清除。
Clean操作在开发和测试阶段是非常有用的,它能够帮助快速有效地更新和重新生成数据库表结构,但特别注意的是:不应在Production的数据库上使用!
Info
Info用于打印所有Migrations的详细和状态信息,其实也是通过Metadata表和Migrations完成的,下图很好地示意了Info打印出来的信息。
Info能够帮助快速定位当前的数据库版本,以及查看执行成功和失败的Migrations。
Validate
Validate是指验证已经Apply的Migrations是否有变更,Flyway是默认是开启验证的。
Validate原理是对比Metadata表与本地Migrations的Checksum值,如果值相同则验证通过,否则验证失败,从而可以防止对已经Apply到数据库的本地Migrations的无意修改。
Baseline
Baseline针对已经存在Schema结构的数据库的一种解决方案,即实现在非空数据库中新建Metadata表,并把Migrations应用到该数据库。
Baseline可以应用到特定的版本,这样在已有表结构的数据库中也可以实现添加Metadata表,从而利用Flyway进行新Migrations的管理了。
Repair
Repair操作能够修复Metadata表,该操作在Metadata表出现错误时是非常有用的。
Repair会修复Metadata表的错误,通常有两种用途:
移除失败的Migration记录,该问题只是针对不支持DDL事务的数据库。
重新调整已经应用的Migratons的Checksums值,比如:某个Migratinon已经被应用,但本地进行了修改,又期望重新应用并调整Checksum值,不过尽量不要这样操作,否则可能造成其它环境失败。
如何使用Flyway?
目前在项目web-server中集成flyway
1.引入依赖
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.1.4</version>
</dependency>
> 2.配置类
> ```swift
@Bean(initMethod = "migrate")
Flyway flyway() {
Map<Object, Object> tenantDataSources = new HashMap<>();
DataSource dataSource = getTenantDataSource(tenantDataSources);
URL tenantResource = ClassLoader.getSystemResource("com/gsoft/db/tenant");
//租户数据库升级
tenantDataSources.forEach((name, ds) -> {
logger.info("=====升级" + name + "租户库=====");
Flyway customFlyway = new Flyway();
customFlyway.setEncoding("UTF-8");
customFlyway.setBaselineOnMigrate(true);
String[] strings = {"db/tenant"};
if (tenantResource != null) {
strings = new String[]{"db/tenant", "classpath:com.gsoft.db.tenant"};
}
customFlyway.setLocations(strings);
customFlyway.setDataSource((DataSource) ds);
customFlyway.migrate();
});
//主库升级
logger.info("=====升级主数据库=====");
URL masterResource = ClassLoader.getSystemResource("com/gsoft/db/master");
Flyway flyway = new Flyway();
flyway.setEncoding("UTF-8");
flyway.setBaselineOnMigrate(true);
String[] strings = {"db/master"};
if (masterResource != null) {
strings = new String[]{"db/master", "classpath:com.gsoft.db.master"};
}
flyway.setLocations(strings);
flyway.setDataSource(dataSource);
return flyway;
}
这里配置了两种方式,一种通过sql脚本进行升级,一种是通过java代码执行sql语句。
1.在resources目录下的db/master(tenant)放置sql脚本,脚本名称必须严格按照V${年月日}__描述.sql
2.在com.gsoft包下新建包db.master(tenant),新建java类实现SpringJdbcMigration接口,实现方法migrate,传入参数为JdbcTemplate,类名必须为V${年月日}__描述,且不能与sql脚本相同。
项目启动以后就可以看到数据库中多了一张表schema_version记录版本升级