SpringBoot數據庫管理 - 用flyway對數據庫管理和遷移

上文介紹了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)定義的更細,包含如下三種:

  1. 版本變遷(Versioned Migrations): 每個版本執行一次,包含有版本、描述和校驗和;常用於創建,修改,刪除表;插入,修改數據等
  2. 撤銷變遷(Undo Migrations): 版本變遷(Versioned Migrations)的反操作。
  3. 可重複變遷(Repeatable Migrations): 可以執行多次,包含描述和校驗和(沒有版本);主要用於視圖,存儲過程,函數等

這三種類型對應的格式如下:

  1. 前綴: V 代表版本變遷(Versioned Migrations), U 代表撤銷變遷(Undo Migrations), R 代表可重複變遷(Repeatable Migrations)
  2. 版本號: 唯一的版本號,比如V1.0.1
  3. 分隔符: __ (兩個下劃線)
  4. 描述信息: 描述信息
  5. 後綴: .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版本還需要使用企業版。就是爲了收費,折騰...。

示例源碼

https://github.com/realpdai/tech-pdai-spring-demos

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章