老板:把數(shù)據(jù)庫變更,給整利索了
本文轉(zhuǎn)載自微信公眾號「小姐姐味道」,作者小姐姐養(yǎng)的狗。轉(zhuǎn)載本文請聯(lián)系小姐姐味道公眾號。
經(jīng)過千難萬險的開發(fā),系統(tǒng)終于上線了,進入了更加驚險刺激的捉蟲階段。在修修補補之中,給后人留下一堆屎山之前,我們需要把數(shù)據(jù)庫給整利索了。
想想吧,我們在開發(fā)環(huán)境,修改了多個字段的名稱,經(jīng)歷了測試環(huán)境的洗禮,還搞了個預上線接受變更。結(jié)果,僅僅在線上忘了操作其中一條SQL,就前功盡棄。如果你做的是項目類型的工作,客戶半年六個月才升級一次,這些腳本的管理就會亂上加亂。
我們需要把這些數(shù)據(jù)庫變更,使用git這樣的工具管理起來,在系統(tǒng)啟動的時候,能夠自動變更。通過口口相傳,太不可信了。
誰也不想背這個鍋。翻聊天記錄?有用么?都是事后諸葛亮。
人和動物的區(qū)別,就是使用工具。經(jīng)常被使用的兩個,有Liquibase和Flyway。但是,Liquibase的遷移腳本寫起來太復雜,需要花很多時間維護,遠不如Flyway這樣的開箱即用(犧牲跨平臺)。如果你的項目不是非常復雜,對Liquibase也不熟悉,建議直接選用flyway。
一般,數(shù)據(jù)庫變更,會有下面幾種語句,我們都可以使用flyway來完成。
- DDL 建表和索引的時候,用到的語句,比如CREATE、ALTER、DROP等
- DML 就是一些常見的數(shù)據(jù)操作語句,比如update、delete、insert
- DCL 用來設置和管理權(quán)限方面信息的語句,比如grant、deny、revoke等
下面,就以flyway為例,來看一下數(shù)據(jù)庫的版本,是如何變更的。
1. flyway migrate
首先,使用mvn的命令,創(chuàng)建一個示范項目。
- mvn archetype:generate -B \
- -DarchetypeGroupId=org.apache.maven.archetypes \
- -DarchetypeArtifactId=maven-archetype-quickstart \
- -DarchetypeVersion=1.1 \
- -DgroupId=foo \
- -DartifactId=bar \
- -Dversion=1.0-SNAPSHOT \
- -Dpackage=foobar
在pom.xml文件中加入下面的內(nèi)容:
- <build>
- <plugins>
- <plugin>
- <groupId>org.flywaydb</groupId>
- <artifactId>flyway-maven-plugin</artifactId>
- <version>7.3.1</version>
- <configuration>
- <url>jdbc:h2:file:./target/foobar</url>
- <user>sa</user>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- <version>1.4.200</version>
- </dependency>
- </dependencies>
- </plugin>
- </plugins>
- </build>
創(chuàng)建數(shù)據(jù)庫變更目錄。
- mkdir -p src/main/resources/db/migration
創(chuàng)建新的數(shù)據(jù)庫文件,我們把它叫做第一個版本:src/main/resources/db/migration/V1__Create_person_table.sql
- create table PERSON (
- ID int not null,
- NAME varchar(100) not null
- );
使用mvn命令,即可完成數(shù)據(jù)庫更新。不要怕,這個命令是冪等的。
- mvn flyway:migrate
終端將輸出下面的內(nèi)容:
- [INFO] Database: jdbc:h2:file:./target/foobar (H2 1.4)
- [INFO] Successfully validated 1 migration (execution time 00:00.009s)
- [INFO] Creating Schema History table: "PUBLIC"."flyway_schema_history"
- [INFO] Current version of schema "PUBLIC": << Empty Schema >>
- [INFO] Migrating schema "PUBLIC" to version 1 - Create person table
- [INFO] Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.038s)
下面,我們準備第二個變更,同樣的,我們創(chuàng)建第二版本的文件:src/main/resources/db/migration/V2__Add_people.sql
下面是SQL文件的內(nèi)容:
- insert into PERSON (ID, NAME) values (1, 'Axel');
- insert into PERSON (ID, NAME) values (2, 'Mr. Foo');
- insert into PERSON (ID, NAME) values (3, 'Ms. Bar');
再次執(zhí)行mvn flyway:migrate,可以發(fā)現(xiàn)第二版本的DML信息,已經(jīng)被寫入到數(shù)據(jù)庫。
2. 如何工作?
那flyway是如何做到冪等的呢?我們使用DBeaver來打開這個h2文件。
在JDBC連接處,輸入:jdbc:h2:/private/tmp/bar/target/foobar.mv.db;然后選擇H2 Embedded模式。我們發(fā)現(xiàn),數(shù)據(jù)庫中除了用戶創(chuàng)建的PERSON表,還多了一個叫做flyway_schema_history的表。
讓我們see一see里面的內(nèi)容。使用mvn flyway:info命令,能看到相同的內(nèi)容。
可以看到,這個冪等操作,其實是由一張自動創(chuàng)建的狀態(tài)表,來保證的。里面還躺著一個叫做checksum的字段,李曼存儲的是一個CRC32值,用來判斷你的SQL文件是否經(jīng)過了非法篡改(篡改后將不予通過)。
捅破了這層窗戶紙,一切神奇的事情忽然就變得豁然開朗。所以如果你想要用flyway,你的賬戶,應該起碼給create table的權(quán)限,否則你就需要手動建這種表。
從上面的SQL文件定義,也可以看出來,這些文件,需要遵循一定的規(guī)律。大體如上圖所示,包含:
- 前綴
- 版本號
- 分隔符
- 版本描述
flyway就是靠這種約定,來進行庫表變更的。所以,要嚴格按照它的要求去命名Sql文件。
3. SpringBoot項目集成
在pom中加入flyway的坐標??梢钥吹轿覀兪菦]有提供版本號的,說明它已經(jīng)在bom文件中定義過了。而它的autoconfigure,在SpringBoot的autoconfigure包里面默認提供了。
- <dependencies>
- <dependency>
- <groupId>org.flywaydb</groupId>
- <artifactId>flyway-core</artifactId>
- </dependency>
- ...
- </dependencies>
我們當然要看一下FlywayProperties這個文件所定義的配置項??梢钥吹剿那熬Y,就是spring.flyway。
默認的DB變更文件,放在classpath:db/migration,我們也可以通過locations配置自定義一個,比如classpath:cn/xjjdog/flyway。當然,也可以通過table屬性,定義那張his表的名稱。url、user、password這些,也可以提供,把his表存儲在和業(yè)務表不一樣的地方。如果不提供,將默認使用datasource所定義的庫。
所以,最小配置,就是什么都不做,直接把變更文件,扔在變更目錄下面就可以了。
- spring:
- datasource:
- # jdbc配置...
- flyway:
- enable: true
- locations: classpath:cn/xjjdog/flyway
End
一根頭發(fā)一寸金,寸金難買寸光陰。
隨著時間的遷移,代碼和sql,都會變成屎一樣的東西。如何在軟件的生命中周期結(jié)束之前,讓我們的工程師,活的幸福一點,才是我們該做的。
作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個人微信xjjdog0,歡迎添加好友,進一步交流。