1.Flyway是什么
- Flyway 对数据库进行版本控制的方式,是在指定数据库中创建一张表,即 Schema History Table(默认为 flyway_schema_history),记录由 Flyway 所执行的 sql 脚本状态。对应 SQL 文件可放置在 src/main/resources/db/migration 下。其中版本号必须全局(一个 Schema History Table 里)唯一,且默认情况下(可通过参数调整)版本号只能增加,不能在已经执行了高版本的 migration 之后再执行低版本的 migration。
- 需要保证数据库flyway_schema_history表中有多少行数据,程序中就应该有多少个对应版本的sql文件。也就是说脚本内容不是在原文件中做修改,而是新建一个sql文件做修改,并命名一个新的版本号。如果修改已经导入成功的脚本文件,会因为checksum校验导致报错,因此要修改原脚本文件,要么删除flyway_schema_history表,要么新加一份文件,并且版本号增加。
- Flyway 的 migration 会在 Spring Boot 应用启动时自动执行。
- 通过 Spring Boot 自动执行 migration 时要注意,一旦 migration 执行失败,应用启动会终止。出现 migration 执行失败时,需要将 Schema History Table 表中的失败记录处理掉,才能再次执行 migration,否则应用会一直无法启动。
注意:启用flyway后,凡是对数据库结构做的修改都不允许直接在库里修改,而是应该在 src/main/resources/db/migration 下新建sql文件,由程序自动执行sql,否则无法保持各地数据库结构一致。
2.为什么用Flyway
在多人开发的项目中,我们习惯了使用SVN或者Git对代码做版本控制,目的是解决多人开发代码冲突和版本回退。
其实,数据库的变更也需要版本控制,在日常开发中,我们经常会遇到下面的问题:
- 自己写的SQL忘了在所有环境执行;
- 别人写的SQL我们不能确定是否都在所有环境执行过了;
- 有人修改了已经执行过的SQL,期望再次执行;
- 需要新增环境做数据迁移;
- 每次发版需要手动控制先发DB版本,再发布应用版本;
3.如何使用Flyway
首先,在pom文件中引入flyway的核心依赖包
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.4</version>
</dependency>
其次,在src/main/resources目录下面新建db.migration文件夹,默认情况下,该目录下的.sql文件就算是需要被flyway做版本控制的数据库SQL语句。
但是此处的SQL语句命名需要遵从一定的规范,否则运行的时候flyway会报错。命名规则主要有两种:
- 仅需要被执行一次的SQL命名以大写的"V"开头,后面跟上"0~9"数字的组合,数字之间可以用“.”或者下划线"_"分割开,然后再以两个下划线分割,其后跟文件名称,最后以.sql结尾。比如,V2.1.5__create_user_ddl.sql、V4.1_2__add_user_dml.sql。
- 可重复运行的SQL,则以大写的“R”开头,后面再以两个下划线分割,其后跟文件名称,最后以.sql结尾。。比如,R__truncate_user_dml.sql。
其中,V开头的SQL执行优先级要比R开头的SQL优先级高。
flyway配置
spring:
# flyway配置
flyway:
# 是否开启 flyway,默认就是开启的
enabled: true
# 告诉 Flyway 在执行 sql 脚本之前,数据库是非空状态
baseline-on-migrate: true
# 它表示是否要清除已有库下的表,如果执行的脚本是 V1__xxx.sql,那么会先清除已有库下的表,然后再执行脚本,这在开发环境下还挺方便,但是在生产环境下就要命了,而且它默认就是要清除,生产环境一定要自己配置设置为 true,建议在所有环境都禁用 Clean 命令
clean-disabled: true
# sql脚本的目录,默认是 classpath:db/migration
locations: classpath:db
# 配置数据库信息表的名称,sql执行记录表
table: flyway_schema_history
# 忽略指定版本以及之前的所有migration
baseline-version: 0
encoding: UTF-8
# 在迁移时,是否校验脚本,假设V1.0__初始.sql已经迁移过了,在下次启动时会校验该脚本是否有变更过,则抛出异常
validate-on-migrate: false
url: jdbc:mysql://127.0.0.1:3306/flyway?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
user: root
password: xxxxxx