Liquibase 筆記
来源:互联网 发布:女生做数据运营 编辑:程序博客网 时间:2024/06/06 06:42
Liquibase 筆記
- 執行Liquibase指令的方式
- maven goals:
- 同步到xml到db
- 建立user table
- 加入額外的欄位
- insert data
- 版控說明
- 完整的 db.changelog-master.xml
- 從資料庫產生changelog.xml
- 只產生data
- 同時產生schema + data
- 完整的pom.xml
- 個人心得
- resource
Liquibase是資料庫版本管理工具,設定的概念是把資料庫schema的異動(table的建立,column的異動,index的異動…)及資料內容的異動(insert,update,delete)用Liquibase定義的語法寫成xml格式change log,然後在資料庫裡多建立一個名為databasechangelog的table(如下),用來記錄db更新了那些change log,當xml新增了更多的change log後,跟db裡的版號一比對,就可得知未同步的change log有那些,下次同步時,就會同步這些未同步過的change log。概念上跟 git 滿像的。
liquibase會在管理的database中加入databasechangelog table,用來記錄與xml同步的狀態
mydb=# select * from databasechangelog;-[ RECORD 1 ]-+--------------------------------------------------------------------------------------------------id | 1author | bobfilename | /Users/kent/dev/liquibase-exercise/src/main/resources/db.changelog-master.xmldateexecuted | 2014-08-30 10:28:35.235724orderexecuted | 1exectype | EXECUTEDmd5sum | 7:17a94fcdd73aa8852c1f53e4d06ee651description | createTablecomments |tag |liquibase | 3.2.2
需特別注意,change log設定檔,一旦同步過後,如果設定檔中的id,檔案路徑等tag有改到,就會被當成新的change log,再次被同步到db中
執行Liquibase指令的方式
要執行Liquibase指令,可透過command line,ant,maven,或API呼叫,本文採用maven的方式。
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>3.2.2</version> <configuration> <changeLogFile>${basedir}/src/main/resources/db.changelog-master.xml</changeLogFile> <outputChangeLogFile>${basedir}/src/main/resources/output.xml</outputChangeLogFile> <driver>org.postgresql.Driver</driver> <url>jdbc:postgresql://localhost:5432/mydb</url> <username>postgres</username> <password>postgres</password> <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase> </configuration> </plugin>
- changeLogFile : 記錄要套用到db的xml檔(xml -> db),執行update指令時,會依changeLogFile的內容異動資料庫schema
- outputChangeLogFile: 從資料庫匯出xml時,會匯出到outputChangeLogFile (db -> xml)
maven goals:
- changelogSync : 將changelog中未套用至db的change logs標示成已同步
- changelogSyncSQL : 同
changelogSync
,但只產生sql,而不執行同步到db - generateChangeLog : 將目前資料庫的shcema(預設不含資料內容)匯出成 xml
- dbDoc : 產生像java doc的文件
- diff : 比對兩個資料庫間的差異
- status : 顯示目前change set有那些change log會被套用到db
- tag : 在liquibase產生在db的管理用table打上tag,之後可以當作rollback用
- update : 更新未套用過的change set至db(xml -> db)
- updateSQL : 同update,但產生更新的sql語法,不會真正同步db
以下的指令沒用過,不太清楚實際的動作情形:
- clearCheckSums :Clears all checksums in the current changelog, so they will be recalculatednext update.
- dropAll : Drops all database objects owned by the user. Note that functions, procedures and packages are not dropped.
- futureRollbackSQL : Generates the SQL that is required to rollback the database to current state after the next update.
- listLocks : Lists all Liquibase updater locks on the current database.
- releaseLocks : Removes any Liquibase updater locks from the current database.
- rollback : Invokes Liquibase rollbacks on a database.
- rollbackSQL : Generates the SQL that is required to rollback the database to the specified pointing attributes ‘rollbackCount’, ‘rollbackTag’
- updateTestingRollback : Applies the DatabaseChangeLogs to the database, testing rollback. This is done by updating the database, rolling it back then updating it again.
像 changelogSync,changelogSyncSQL,或 update,updateSQL,做的事情是差不多的,而有SQL後綴的版本,是會把要執行的SQL語法輸出到stdout,而不進行db的更新。
在使用上,新的database,一開始就用changelog的xml管理,所有的異動都透過xml管理,然後使用mvn liquibase:update
,就會將plugin中的changeLogFile
指定的 change log檔更新到db,如果是legcy的專案原本就有db的,可以用mvn liquibase:generateChangeLog
把db匯成change log檔案至outputChangeLogFile
指定的檔案中,之後再以產生出來的change log為基礎,做資料庫版本的管理。
同步到xml到db
建立user table
src/main/resources/db.changelog-master.xml
<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <!-- 建立 uesr table --> <changeSet id="create-user-table" author="kent"> <createTable tableName="user"> <column name="first_name" type="varchar(50)"> <constraints nullable="false"/> </column> <column name="last_name" type="varchar(50)"> </column> </createTable> </changeSet></databaseChangeLog>
第一次執行mvn liquibase:update
執行後,原本完全沒有table的db多了三個table,
- databasechangelog是記錄同步用的,
- databasechangeloglock是做locking的
上面兩個都是直接由liquibase管理,不用去管它。
- user 則是上面的change log中的
<createTable>
建立的
List of relations Schema | Name | Type | Owner--------+-----------------------+-------+---------- public | databasechangelog | table | postgres public | databasechangeloglock | table | postgres public | user | table | postgres
user跟change log中定義的結構是一致的
Table "public.user" Column | Type | Modifiers------------+-----------------------+----------- first_name | character varying(50) | not null last_name | character varying(50) |
加入額外的欄位
src/main/resources/db.changelog-master.xml
<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> ...(略) <!-- 在user table加入 address column --> <changeSet id="addColumn-example" author="kent"> <addColumn catalogName="mydb" schemaName="public" tableName="user"> <column name="address" type="varchar(255)"/> </addColumn> </changeSet></databaseChangeLog>
改完changelog的xml檔,再次執行mvn liquibase:update
後,user table就會多出address column,這次執行,因為databasechangelog中已有記錄<changeSet id="create-user-table" author="kent">
已經被執行過了,所以不會再次被執行。
Table "public.user" Column | Type | Modifiers------------+------------------------+----------- first_name | character varying(50) | not null last_name | character varying(50) | address | character varying(255) |
insert data
src/main/resources/db.changelog-master.xml
<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> ...(略) <!-- insert兩筆測試資料 --> <changeSet id="insert-example" author="kent" > <insert catalogName="mydb" schemaName="public" tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> </insert> <insert catalogName="mydb" schemaName="public" tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> </insert> </changeSet></databaseChangeLog>
改完changelog的xml檔,執行mvn liquibase:update
執行後,user table就會多出兩筆資料
first_name | last_name | address------------+-----------+--------- kent | chiu | cindy | chiu |
版控說明
在實務上,只要是db的schema有要做異動,就一律從change log的設定檔改,如果是資料內容的異動,則視需求看要不要從change log異動。必要的預設資料可以在change log裡,透過insert tag來建立,可以省去每次重建table都還要另外建立預設資料的步驟。
搭配其他指令,還可以讓資料庫回到特一個特定的版本(change set),這樣在開發時,就不用怕弄亂資料庫了。
完整的 db.changelog-master.xml
<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <!-- 建立 uesr table --> <changeSet id="create-user-table" author="kent"> <createTable tableName="user"> <column name="first_name" type="varchar(50)"> <constraints nullable="false"/> </column> <column name="last_name" type="varchar(50)"> </column> </createTable> </changeSet> <!-- 在user table加入 address column --> <changeSet id="addColumn-example" author="kent"> <addColumn catalogName="mydb" schemaName="public" tableName="user"> <column name="address" type="varchar(255)"/> </addColumn> </changeSet> <!-- insert兩筆測試資料 --> <changeSet id="insert-example" author="kent" > <insert catalogName="mydb" schemaName="public" tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> </insert> <insert catalogName="mydb" schemaName="public" tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> </insert> </changeSet></databaseChangeLog>
從資料庫產生changelog.xml
對於即有的database,可以透過generateChangeLog
從資料庫產生change log,再以這個change log檔為基礎,之後的異動,再透過liquibase管理(xml -> db)
使用generateChangeLog
進行匯出時,預設是只有schema(tables, views, columns, indexs,foreignkeys, primarykeys, uniqueconstraints),如果要產 生資料,要在diffTypes
中加入data這個type。
kent@Kents-MacBook-Pro:~/dev/liquibase-exercise$ mvn liquibase:generateChangeLog[INFO] Scanning for projects...[INFO][INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1[INFO][INFO] ------------------------------------------------------------------------[INFO] Building liquibase-exercise 1.1.0-SNAPSHOT[INFO] ------------------------------------------------------------------------[INFO][INFO] --- liquibase-maven-plugin:3.2.2:generateChangeLog (default-cli) @ liquibase-exercise ---[INFO] ------------------------------------------------------------------------[INFO] Executing on Database: jdbc:postgresql://localhost:5432/mydb[INFO] Generating Change Log from database postgres @ jdbc:postgresql://localhost:5432/mydb (Default Schema: public)INFO 8/30/14 12:30 PM: liquibase: /Users/kent/dev/liquibase-exercise/src/main/resources/output.xml does not exist, creating[INFO] Output written to Change Log file, /Users/kent/dev/liquibase-exercise/src/main/resources/output.xml[INFO] ------------------------------------------------------------------------[INFO][INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 2.087 s[INFO] Finished at: 2014-08-30T12:31:00+08:00[INFO] Final Memory: 8M/61M[INFO] ------------------------------------------------------------------------
執行完generateChangeLog
可以看到change log產生到我們plugin的設定中指定的位置src/main/resources/output.xml
如果沒有特別指定diffTypes
參數,那只會產生’tables, views, columns, indexs,foreignkeys, primarykeys, uniqueconstraints’
<?xml version="1.0" encoding="UTF-8" standalone="no"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd"> <changeSet author="kent (generated)" id="1409373059484-1"> <insert tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> <insert tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> </changeSet> <changeSet author="kent (generated)" id="1409373299327-1"> <createTable tableName="user"> <column name="first_name" type="VARCHAR(50)"> <constraints nullable="false"/> </column> <column name="last_name" type="VARCHAR(50)"/> <column name="address" type="VARCHAR(255)"/> </createTable> </changeSet></databaseChangeLog>
只產生data
指定diffTypes=data
,就會只產生資料,不會有schema的資訊,如果有需要,也可以直接將資料匯出成csv檔
mvn liquibase:generateChangeLog -Dliquibase.diffTypes=data
產生的xml如下
<?xml version="1.0" encoding="UTF-8" standalone="no"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd"> <changeSet author="kent (generated)" id="1409373576402-1"> <insert tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> <insert tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> </changeSet></databaseChangeLog>
同時產生schema + data
如果要產生的xml如下,那diffTypes
就要設定為tables,views,columns,indexs,foreignkeys,primarykeys,uniqueconstraints,data
mvn liquibase:generateChangeLog -Dliquibase.diffTypes=tables,views,columns,indexs,foreignkeys,primarykeys,uniqueconstraints,data
產生的xml如下
<?xml version="1.0" encoding="UTF-8" standalone="no"?><databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd"> <changeSet author="kent (generated)" id="1409373576402-1"> <insert tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> <insert tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> </changeSet> <changeSet author="kent (generated)" id="1409373769747-1"> <createTable tableName="user"> <column name="first_name" type="VARCHAR(50)"> <constraints nullable="false"/> </column> <column name="last_name" type="VARCHAR(50)"/> <column name="address" type="VARCHAR(255)"/> </createTable> </changeSet> <changeSet author="kent (generated)" id="1409373769747-2"> <insert tableName="user"> <column name="first_name" value="kent"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> <insert tableName="user"> <column name="first_name" value="cindy"/> <column name="last_name" value="chiu"/> <column name="address"/> </insert> </changeSet></databaseChangeLog>
完整的pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kent</groupId> <artifactId>liquibase-exercise</artifactId> <version>1.1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.3-1101-jdbc41</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>3.2.2</version> <configuration> <changeLogFile>${basedir}/src/main/resources/db.changelog-master.xml</changeLogFile> <outputChangeLogFile>${basedir}/src/main/resources/output.xml</outputChangeLogFile> <driver>org.postgresql.Driver</driver> <url>jdbc:postgresql://localhost:5432/mydb</url> <username>postgres</username> <password>postgres</password> <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase> <!-- 同時產生資料跟schema --> <!-- <diffTypes>tables, views, columns, indexs,foreignkeys, primarykeys, uniqueconstraints, data</diffTypes> --> </configuration> </plugin> </plugins> </build></project>
個人心得
會接觸liquibase,主要是因為維護的專案,是屬於產品類型的,一但delivery給客戶後,要昇級程式,常不可避免的會動到db的結構或資料。 新增table跟column通常都不太會有問題,但是如果是要做delete或rename,甚至是對即有資料內容做一些格式的調整或轉換,一些簡單的sql指令(ddl或dml)就有點使不上力了,可能就要寫一些sql的funciton來處理,如果邏輯更複雜時就需要用程式處理,
在當時並沒有比較適合的solution,於是採用了類似Ruby On Rails管資料庫版本的方式做了一套,大部份的異動,都還是希望透過 sql script就能處理,但有些最基本的判斷,像column存不存在,不存在就建立,或column的rename,這些透過sql也不是很好處理,通常都要透過自製的sql function來處理,如果比較複雜的,就寫一個小程式來取代原來的sql script,使用上並不方便,而且 維護成本也不小,光每次測試sql patch,所以這次斷然決定換成用liquibase來管理,看看會不會有顯著的改善,目前看來使用經 驗算是不錯。
resource
- http://www.liquibase.org/documentation/maven/index.html - liquibase maven plugin
- Liquibase 筆記
- liquibase
- Liquibase+spring
- liquibase安装
- Liquibase使用
- Liquibase 接触
- Liquibase --- Database Change Management
- LiquiBase实战总结
- 如何使用Liquibase
- LiquiBase预判断
- spring boot 配置liquibase
- liquibase入门实战
- liquibase配置(MAVEN)
- 数据库重构工具 LiquiBase(5 Liquibase被锁)
- liquibase-maven-plugin 报错
- 在项目中使用Liquibase
- 使用 LiquiBase 管理数据库变更
- Spring3+Mybatis3+Mysql+ivy+liquibase 集成
- SwitchHosts—hosts管理利器
- swift中的!和?作用
- 什么样的Web开发框架才是好的前端框架
- 剑指offer——59.按之字形顺序打印二叉树
- sockaddr和sockaddr_in的区别
- Liquibase 筆記
- 浅述经典的4种卷积网络之(2)VGGNet
- linux文件合并、去重、拆分
- Linux学习掌握(一):基础的linux命令
- 557. Reverse Words in a String III 难度:简单
- bean with name 'mappingJacksonHttpMessageConverter' defined in class解决办法
- PostgreSQL for Windows安装
- 两个数换位运算(不用第三变量)--异或
- addrinfo结构体与getaddrinfo函数