上文介紹了Liquibase,以及和SpringBoot的集成。除了Liquibase之外,還有一個組件Flyway也是經常被使用到的類似的數據庫版本管理中間件。本文主要介紹Flyway, 以及SpringBoot集成Flyway。@pdai
知識準備
需要了解Flyway和要解決的問題,以及一些基礎概念,比如變遷(migrations),常用命令(commands)等。
什麼是Flyway? 要解決什麼問題?
Flyway是一款數據庫遷移(migration)工具。簡單點說,就是在你部署應用的時候,幫你執行數據庫腳本的工具。Flyway支持SQL和Java兩種類型的腳本,你可以將腳本打包到應用程序中,在應用程序啓動時,由Flyway來管理這些腳本的執行,這些腳本被Flyway稱之爲migration。
PS: 本質上和liquibase機制一致。
按照verion的順序(和數據庫中的更新記錄對比,找到未更新的),更新如下
更新記錄如下
Flyway中的變遷(migrations)
對於Flyway,對數據庫的所有更改都稱爲變遷(migrations),等同於liquibase中的changeset。
在Flyway中變遷(migrations)定義的更細,包含如下三種:
- 版本變遷(Versioned Migrations): 每個版本執行一次,包含有版本、描述和校驗和;常用於創建,修改,刪除表;插入,修改數據等
- 撤銷變遷(Undo Migrations): 版本變遷(Versioned Migrations)的反操作。
- 可重複變遷(Repeatable Migrations): 可以執行多次,包含描述和校驗和(沒有版本);主要用於視圖,存儲過程,函數等
這三種類型對應的格式如下:
- 前綴: V 代表版本變遷(Versioned Migrations), U 代表撤銷變遷(Undo Migrations), R 代表可重複變遷(Repeatable Migrations)
- 版本號: 唯一的版本號,比如V1.0.1
- 分隔符: __ (兩個下劃線)
- 描述信息: 描述信息
- 後綴: .sql
(PS:撤銷變遷(Undo Migrations)在收費版本中)
Flyway中常用命令
Flyway中的常用commands有哪些?什麼含義?
Migrate: 是Flyway工作流的核心。它將掃描文件系統或類路徑以查找可用的Migrate。它將把它們與已應用於數據庫的Migrate進行比較。如果發現任何差異則遷移數據。
Clean: 清除掉對應數據庫Schema中所有的對象,包括表結構,視圖,存儲過程等,clean操作在dev 和 test階段很好用;(PS:不能用在product環境)
Info: 用於打印所有的Migrations的詳細和狀態信息,也是通過MetaData和Migrations完成的,可以快速定位當前的數據庫版本;
Validate: 驗證以及apply的Migrations是否有變更,默認開啓的;原理是對比MetaData表與本地Migrations的checkNum值,如果值相同則驗證通過,否則失敗。
Undo: Migrate的反操作, 即回滾操作,這是收費功能
BaseLine:對已經存在數據庫Schema結構的數據庫一種解決方案。實現在非空數據庫新建MetaData表,並把Migrations應用到該數據庫;也可以應用到已有表結構的數據庫中也可以實現添加Metadata表。
Repair:repair操作能夠修復metaData表,該操作在metadata出現錯誤時很有用
簡單示例
這裏主要介紹基於SpringBoot集成flyway來管理數據庫的變更。
POM依賴
Maven 包的依賴,主要包含mysql驅動, JDBC(這裏spring-boot-starter-data-jpa包含了jdbc包,當然直接引入jdbc包也行),以及flyway包。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
<version>8.5.7</version>
</dependency>
yml配置
SpringBoot AutoConfig默認已經包含了對flyway的配置,在spring.flyway配置下
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db_flyway?useSSL=false&autoReconnect=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: bfXa4Pt2lUUScy8jakXf
flyway:
enabled: true
encoding: UTF-8
# 可以支持多個location, 用','隔開
locations: classpath:db/migration
# migrate是否校驗
validate-on-migrate: true
在開發時,更多的配置可以從如下SpringBoot AutoConfig中找到。
Migrate配置
這裏我們準備兩個Versioned Migration
- V1.0__Init_DB.sql
DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`email` varchar(45) DEFAULT NULL,
`phone_number` int(11) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
- V1.1__Init_Data.sql
LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (1,'pdai','dfasdf','[email protected]',1212121213,'afsdfsaf','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;
測試
啓動springBootApplication, 我們可以看到如下log
2022-04-13 07:56:56.122 INFO 86030 --- [ main] o.f.c.i.database.base.DatabaseType : Database: jdbc:mysql://localhost:3306/test_db_flyway (MySQL 8.0)
2022-04-13 07:56:56.220 INFO 86030 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.074s)
2022-04-13 07:56:56.245 INFO 86030 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `test_db_flyway`.`flyway_schema_history` ...
2022-04-13 07:56:56.270 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.282 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.292 INFO 86030 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test_db_flyway`: << Empty Schema >>
2022-04-13 07:56:56.297 INFO 86030 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `test_db_flyway` to version "1.0 - Init DB"
2022-04-13 07:56:56.309 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Unknown table 'test_db_flyway.tb_user' (SQL State: 42S02 - Error Code: 1051)
2022-04-13 07:56:56.309 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.309 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.310 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous. (SQL State: HY000 - Error Code: 3719)
2022-04-13 07:56:56.310 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.317 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Integer display width is deprecated and will be removed in a future release. (SQL State: HY000 - Error Code: 1681)
2022-04-13 07:56:56.317 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Integer display width is deprecated and will be removed in a future release. (SQL State: HY000 - Error Code: 1681)
2022-04-13 07:56:56.317 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous. (SQL State: HY000 - Error Code: 3719)
2022-04-13 07:56:56.317 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.318 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.333 INFO 86030 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `test_db_flyway` to version "1.1 - Init Data"
2022-04-13 07:56:56.334 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.335 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Table storage engine for 'tb_user' doesn't have this option (SQL State: HY000 - Error Code: 1031)
2022-04-13 07:56:56.335 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.335 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 1 rows affected
2022-04-13 07:56:56.336 WARN 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Table storage engine for 'tb_user' doesn't have this option (SQL State: HY000 - Error Code: 1031)
2022-04-13 07:56:56.337 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.337 INFO 86030 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : 0 rows affected
2022-04-13 07:56:56.346 INFO 86030 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 2 migrations to schema `test_db_flyway`, now at version v1.1 (execution time 00:00.058s)
生成的flyway更新的記錄,test_db_flyway
.flyway_schema_history
已經user表結構和數據
進一步理解
通過幾個問題,進一步理解。
MySQL的支持性問題
從Flyway對MySQL支持性,可以看出官方期望通過MySQL使用的大量基數獲取更多的付費用戶。
首先,如果你只是引入flyway-core:8.5.7的包時,會報如下錯誤
Caused by: org.flywaydb.core.api.FlywayException: Unsupported Database: MySQL 8.0
at org.flywaydb.core.internal.database.DatabaseTypeRegister.getDatabaseTypeForConnection(DatabaseTypeRegister.java:106) ~[flyway-core-8.5.7.jar:na]
at org.flywaydb.core.internal.jdbc.JdbcConnectionFactory.<init>(JdbcConnectionFactory.java:76) ~[flyway-core-8.5.7.jar:na]
at org.flywaydb.core.FlywayExecutor.execute(FlywayExecutor.java:147) ~[flyway-core-8.5.7.jar:na]
at org.flywaydb.core.Flyway.migrate(Flyway.java:124) ~[flyway-core-8.5.7.jar:na]
at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:66) ~[spring-boot-autoconfigure-2.5.3.jar:2.5.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.9.jar:5.3.9]
... 18 common frames omitted
因爲找不到內置的Datebase type
所以你應該引入的包是flyway-mysql:8.5.7,而有意思的是這個包中包含的flyway-core版本是7.7.3
然後我們看下官網對MySQL的支持性,這騷操作,5.7版本還需要使用企業版。就是爲了收費,折騰...。