在項目迭代開發(fā)中谤牡,難免會有更新數(shù)據(jù)庫 Schema 的情況针余,比如添加新表、在表中增加字段或者刪除字段等土居,那么當(dāng)我對數(shù)據(jù)庫進行一系列操作后驶俊,如何快速地在其他同事的電腦上同步娶耍?如何在測試/生產(chǎn)服務(wù)器上快速同步?
每次發(fā)版的時候饼酿,由于大家都可能有 sql 更改情況榕酒,這樣就會有以下痛點:
- 忘記某些 sql 修改
- 每個開發(fā)人員的 sql 的執(zhí)行順序問題
- 重復(fù)更新
- 需要手動去數(shù)據(jù)庫執(zhí)行腳本
以上問題以及痛點可以通過 Flyway 工具來解決,F(xiàn)lyway 可以實現(xiàn)自動化的數(shù)據(jù)庫版本管理故俐,并且能夠記錄數(shù)據(jù)庫版本更新記錄想鹰。
Flyway 簡介
Flyway 是獨立于數(shù)據(jù)庫的應(yīng)用、管理并跟蹤數(shù)據(jù)庫變更的數(shù)據(jù)庫版本管理工具药版。用通俗的話講辑舷,F(xiàn)lyway 可以像 Git 管理不同人的代碼那樣,管理不同人的 sql 腳本槽片,從而做到數(shù)據(jù)庫同步何缓,更多的信息可以在 Flyway 的官網(wǎng)上進行閱讀學(xué)習(xí)。
另外 Flyway 支持很多關(guān)系數(shù)據(jù)庫还栓,具體如下所示:
下面我們在 Spring Boot 中集成 Flyway 來實現(xiàn)數(shù)據(jù)庫版本控制碌廓。
Spring Boot 集成 Flyway
首先創(chuàng)建一個 SpringBoot 項目,然后在 pom.xml
加入如下依賴集成 Flyway:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.4</version>
</dependency>
然后在 application.yml
中寫入 mysql 的配置及 Flyway 的相關(guān)配置(Flyway locations 默認讀取當(dāng)前項目下的 resources/db/migration
目錄)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
spring.flyway.locations=classpath:/db/migration/
接下來剩盒,在 resources/db/migration
目錄下創(chuàng)建需要執(zhí)行的 SQL 腳本即可谷婆。
其中,SQL 腳本命名規(guī)范如下:
- Prefix 前綴:V 代表版本遷移,U 代表撤銷遷移波材,R 代表可重復(fù)遷移
- Version 版本號:版本號通常
.
和整數(shù)組成 - Separator 分隔符:固定由兩個下劃線
__
組成 - Description 描述:由下劃線分隔的單詞組成,用于描述本次遷移的目的
- Suffix 后綴:如果是 SQL 文件那么固定由
.sql
組成身隐,如果是基于 Java 類則默認不需要后綴
那么廷区,我們按照命名規(guī)范在 resources/db/migration
目錄下,創(chuàng)建 V1.0__init_db.sql
SQL 遷移腳本贾铝,具體內(nèi)容如下:
DROP TABLE IF EXISTS `user` ;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(20) NOT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` (`id`, `name`, `age`) VALUES ('1', 'wupx', '18');
最后啟動項目隙轻,執(zhí)行日志如下所示:
2020-05-07 12:41:29.126 INFO 13732 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2020-05-07 12:41:29.236 INFO 13732 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:mysql://localhost:3306/test (MySQL 5.5)
2020-05-07 12:41:29.287 INFO 13732 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.009s)
2020-05-07 12:41:29.330 INFO 13732 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table: `test`.`flyway_schema_history`
2020-05-07 12:41:29.479 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test`: << Empty Schema >>
2020-05-07 12:41:29.480 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema `test` to version 1.0 - init db
2020-05-07 12:41:29.481 WARN 13732 --- [ main] o.f.c.i.s.DefaultSqlScriptExecutor : DB: Unknown table 'user' (SQL State: 42S02 - Error Code: 1051)
2020-05-07 12:41:29.631 INFO 13732 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema `test` (execution time 00:00.301s)
從啟動日志中可以看出,F(xiàn)lyway 監(jiān)測到需要運行版本腳本來初始化數(shù)據(jù)庫垢揩,因此執(zhí)行了 V1.0__init_db.sql
腳本玖绿,從而創(chuàng)建了 user
表,另外還自動創(chuàng)建了 flyway_schema_history
表叁巨,用于記錄所有版本演化和狀態(tài)斑匪,其表結(jié)構(gòu)如下(以 MySQL 為例):
Field | Type | Null | Key | Default |
---|---|---|---|---|
version_rank | int(11) | NO | MUL | NULL |
installed_rank | int(11) | NO | MUL | NULL |
version | varchar(50) | NO | PRI | NULL |
description | varchar(200) | NO | NULL | |
type | varchar(20) | NO | NULL | |
script | varchar(1000) | NO | NULL | |
checksum | int(11) | YES | NULL | |
installed_by | varchar(100) | NO | NULL | |
installed_on | timestamp | NO | CURRENT_TIMESTAMP | |
execution_time | int(11) | NO | NULL | |
success | tinyint(1) | NO | MUL | NULL |
查詢 flyway_schema_history
表,發(fā)現(xiàn)增加了一條版本號為 1.0
的锋勺,使用 V1.0__init_db.sql
遷移腳本的記錄蚀瘸。
mysql> SELECT * FROM flyway_schema_history;
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
| installed_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success |
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
| 1 | 1.0 | init db | SQL | V1.0__init_db.sql | 1317299633 | root | 2020-05-07 12:41:29 | 97 | 1 |
+----------------+---------+-------------+------+-------------------+------------+--------------+---------------------+----------------+---------+
再去查詢 user
表,發(fā)現(xiàn) sql 腳本中的數(shù)據(jù)也插入成功了庶橱。
mysql> SELECT * FROM user;
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | wupx | 18 |
+----+------+-----+
接下來再次運行項目贮勃,結(jié)果如下:
2020-05-07 15:34:49.843 INFO 41880 --- [ main] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 5.2.4 by Boxfuse
2020-05-07 15:34:49.981 INFO 41880 --- [ main] o.f.c.internal.database.DatabaseFactory : Database: jdbc:mysql://localhost:3306/test (MySQL 5.5)
2020-05-07 15:34:50.036 INFO 41880 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.013s)
2020-05-07 15:34:50.043 INFO 41880 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema `test`: 1.0
2020-05-07 15:34:50.043 INFO 41880 --- [ main] o.f.core.internal.command.DbMigrate : Schema `test` is up to date. No migration necessary.
從日志中可以看出,F(xiàn)lyway 發(fā)現(xiàn)一個遷移腳本苏章,也就是 V1.0__init_db.sql
寂嘉,經(jīng)過判斷已經(jīng)到達最新版本 1.0,無需執(zhí)行遷移枫绅。
接下來泉孩,我們在 V1.0__init_db.sql
遷移腳本中添加一條 INSERT 操作:INSERT INTO
user(
id,
name,
age) VALUES ('2', 'huxy', '18');
,再次啟動項目撑瞧,會報如下錯誤:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 1.0
-> Applied to database : 1317299633
-> Resolved locally : -1582367361
這個錯誤的原因就是 Flyway 會給腳本計算一個 checksum 保存在數(shù)據(jù)庫中棵譬,用于在之后運行過程中對比 sql 文件是否有變化,如果發(fā)生了變化预伺,則會報錯订咸,也就防止了誤修改腳本導(dǎo)致發(fā)生問題。
總結(jié)
Flyway 可以有效改善數(shù)據(jù)庫版本管理方式酬诀,并且是一款 Java 開源的數(shù)據(jù)庫遷移管理工具脏嚷,具有輕便小巧的特點,可以無門檻快速集成到項目中瞒御,如果項目中還未使用父叙,不防嘗試一下,想了解更多的可以去官網(wǎng)查看文檔學(xué)習(xí)。
本文的完整代碼在 https://github.com/wupeixuan/SpringBoot-Learn 的 database-version-control
目錄下趾唱。
最好的關(guān)系就是互相成就涌乳,大家的在看、轉(zhuǎn)發(fā)甜癞、留言三連就是我創(chuàng)作的最大動力夕晓。
參考