首发地址,欢迎查看:https://www.pengtao.vip/archives/liquibasejianjiejispringbootjichengshiyong
Liquibase是什么
Liquibase 是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制。
Liquibase能干嘛
- 不依赖于特定的数据库,目前支持包括
Oracle/SqlServer/DB2/MySql/Sybase/PostgreSQL
等几十种数据库,这样在数据库的部署和升级环节可帮助应用系统支持多数据库。 - 提供数据库比较功能,比较结果保存在XML中,基于该XML你可用 Liquibase 轻松部署或升级数据库。
- 以XML存储数据库变化,其中以
author
和id
唯一标识一个更改集ChangeSet,支持数据库变化的合并,因此支持多开发人员同时工作。 - 在数据库中保存数据库修改历史(DatabaseChangeHistory),在数据库升级时自动跳过已应用的更改集。
- 提供变化应用的回滚功能,可按时间、数量或标签(tag)回滚已应用的更改集。通过这种方式,开发人员可轻易的还原数据库在任何时间点的状态。
- 可生成数据库修改文档(HTML格式)
- 提供数据重构的独立的IDE和Eclipse插件。
基本概念
使用 Liquibase
时,可以使用 Liquibase 函数或 SQL 定义更改。重要的是,这些模式不是互斥的,可以结合使用,从而在如何定义和部署数据库更改方面提供了相当大的灵活性。对于使用 Liquibase
函数定义的更改,Liquibase
生成适合目标数据库的SQL
。这在下列场景是很有用的:
- 支持多个不同的数据库后端。
- 使不熟悉
SQL
或不熟悉SQL
的开发人员能够定义数据库更改。数据库迁移可以在XML
、JSON
或YAML
中定义,而不是SQL
。 - 标准化数据库更改。
Liquibase
将生成语法和风格上一致的SQL
,例如,确保所有CREATE TABLE
迁移具有相同的样式和模式。
changelog文件
changelog
是LiquiBase用来记录数据库的变更,一般放在CLASSPATH
下,然后配置到执行路径中。 所有 Liquibase
更改的根目录是databaseChangeLog
文件。
changelog支持多种格式,主要有 XML/JSON/YAML/SQL
,其中XML/JSON/YAML
除了具体格式语法不同,节点配置很类似,SQL
格式中主要记录SQL语句。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">
</databaseChangeLog>
preConditions
:执行更改日志所需的先决条件。property
:将属性设置为的值。changeSet
:要执行的changeSet
。include
:包含要执行的changeSet
的其他文件。
当 Liquibase
迁移器运行时,它将分析数据库 ChangeLog
标记。它首先检查指定的先决条件。如果先决条件失败,Liquibase
将退出,并显示一条错误消息,解释失败的原因。先决条件对于记录和强制执行更改日志编写器的预期和假设(如要针对的 DBMS
或以用户身份运行更改)非常有用。
如果满足所有的先决条件,Liquibase
将会开始运行在databaseChangeLog
文件中按照顺序出现的changeSet
和include
标签。
ChangeSet标签
changeSet
由author
和id
属性以及changelog
文件的位置唯一标识,是 Liquibase
跟踪执行的单位。运行 Liquibase
时,它会查询标记为已执行的changeSet
的DATABASECHANGELOG
表,然后执行更改日志文件中尚未执行的所有changeSet
。
changeSet
作为一次变更的单位,可以是新建一张表、加一列,插入数据、删除索引等。升级与回滚都是以changeset
为单位的;每个changeset
会通过id
和author
来标记。
多环境动态标识替换:
不同数据库字段标识是不一样的,语法也会有不同,通过定义属性,能解决这个问题
<property name="clob.type" value="clob" dbms="oracle,postgresql"/>
<property name="clob.type" value="longtext" dbms="mysql"/>
<property name="table.name" value="tableA"/>
<changeSet id="1" author="joe">
<createTable tableName="${table.name}">
<column name="id" type="int"/>
<column name="column1" type="${clob.type}"/>
<column name="column2" type="int"/>
</createTable>
</changeSet>
preConditions标签
先决条件可以应用于整个changelog
或单个changeSet
。如果先决条件失败,liquibase
将停止执行。
<preConditions>
<dbms type="oracle" />
<runningAs username="SYSTEM" />
</preConditions>
<changeSet id="1" author="bob">
<preConditions onFail="WARN">
<sqlCheck expectedResult="0">select count(*) from oldtable</sqlCheck>
</preConditions>
<comment>Comments should go after preCondition. </comment>
<dropTable tableName="oldtable"/>
</changeSet>
示例表示数据库为Oracle
,数据库的用户名为SYSTEM
才允许执行上述databasechangelog
。仅当"oldtable"中没有值时,它才会运行 dropTable
命令,可以防止配置错误和升级错误。expectedResult
这个值与SQL
的执行结果作比较,必填
preConditions有以下属性:
onFail
: 当proConditions
遇到失败的时候如何处理onError
:当proConditions
遇到错误的时候如何处理onUpdateSQL
:自版本1.9.5后当proConditions
遇到更新SQL
模型的时候如何处理onFailMessage
:自2.0起,在proConditions
失败时要输出的自定义消息。onErrorMessage
:在proConditions
错误时要输出的自定义消息。
可以使用可嵌套<and>
、<or>
和<not>
标签将条件逻辑应用于preConditions
。如果未指定条件标签,则默认为 <AND>
。
<preConditions>
<or>
<and>
<dbms type="oracle" />
<runningAs username="SYSTEM" />
</and>
<and>
<dbms type="mysql" />
<runningAs username="sa" />
</and>
</or>
</preConditions>
如果对 Oracle
数据库执行,则需要以 SYSTEM
身份运行;如果对MySQL
数据库运行,则需要以 SA
身份运行。
Contexts标签
Liquibase
中的context
是可以添加到changeSet
的标签,以控制将在任何特定的迁移运行中执行哪些设置。任何字符串都可用于上下文名称,并且它们处于不区分大小写状态。
通过任何可用方法运行迁移器时,可以传递一组要运行的context
。将仅运行使用已传递上下文标记的changeset
。在你迁移的时候如果没有指定一个具体的context
,那么所有的context
都会执行。
语法:context语法具体是使用AND
,OR
,!
和圆括号
。在没有圆括号的情况下,操作的顺序是!
,AND
,OR
context="!test"
context="v1.0 or map"
context="v1.0 or map"
context="!qa and !master"
使用 ,
来分隔上下文的工作方式类似于 OR
操作,但具有最高的优先级。
"test,qa"
等价于test OR qa
"test,qa and master"
等价于test OR (qa AND master)
Rollback标签
-
回滚标记描述如何对
SQL
语句、change tag
或以前的changeSet
的引用进行回滚更改。 -
多个语句可以被包含在一个
<rollback>
标签中。一个changeSet
中可以有多个rollback
标签 -
DATABASECHANGELOG
表用于记录被执行过的changeset
,当回滚后,就会删去被回滚掉的记录。 -
版本回滚 可以使用命令行 或者
maven
,ant
等构建工具来完成。
<changeSet id="changeRollback" author="nvoxland">
<createTable tableName="changeRollback1">
<column name="id" type="int"/>
</createTable>
<rollback>
<dropTable tableName="changeRollback1"/>
</rollback>
</changeSet>
项目整合
Spring Boot 集成 Liquibase
首先新建一个spring boot项目,在pom文件添加以下依赖:
<!--用来连接数据库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--数据库连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!--Liquibase-->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.4.3</version>
</dependency>
配置 application.yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/liquibase?serverTimezone=UTC
username: root
password:
liquibase:
enabled: true
change-log: classpath:db_changelog/changelog-master.yaml
在resources
下创建changelog
文件夹,并在该文件夹下创建changelog-master.yaml
配置文件和分类配置文件夹,用来将每次的liquibase脚本放在相应文件夹里,每个文件夹里都是一个小的liquibase配置脚本。
在changelog-master.yaml
中引入子脚本
databaseChangeLog:
- include:
file: db_changelog/liquibase.mysql/changelog-202109-ddl.xml
- include:
file: db_changelog/liquibase.mysql/changelog-202109-dml.xml
配置脚本demo
<?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-4.4.xsd">
<changeSet id="1" author="penguin">
<createTable tableName="distributor">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="address" type="varchar(255)">
<constraints nullable="true"/>
</column>
<column name="active" type="boolean" defaultValue="1"/>
</createTable>
</changeSet>
</databaseChangeLog>
启动项目,可以发现在数据库下已经创建了相应的表,可以看到数据库现在额外创建了另外两个表:databasechangelog
和 databasechangeloglock
。
- databasechangelog表包含已针对数据库运行的所有语句的列表。
- databasechangeloglock表用于确保两台计算机不会同时尝试修改数据库。
Liquibase 管理数据库变更
本节将介绍 5 种:添加列(Add Column)、删除列(Drop Column)、创建表(Create Table)、引入SQL脚本和操作数据。
添加列
<changeSet id="4" author="penguin">
<addColumn tableName="distributor">
<column name="phonenumber" type="varchar(255)"/>
</addColumn>
</changeSet>
删除列
<dropColumn tableName="distributor" columnName="phonenumber"/>
创建表
<changeSet id="3" author="penguin">
<createTable tableName="distributor">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="address" type="varchar(255)">
<constraints nullable="true"/>
</column>
<column name="active" type="boolean" defaultValue="1"/>
</createTable>
</changeSet>
操作数据
<changeSet id="2" author="penguin">
<insert tableName="distributor">
<column name="id" valueNumeric="3"/>
<column name="name" value="Pan"/>
</insert>
<insert tableName="distributor">
<column name="id" valueNumeric="4"/>
<column name="name" value="Soft"/>
</insert>
</changeSet>
引入SQL脚本
<changeSet id="6" author="penguin">
<sqlFile path="insert-distributor-data.sql"/>
</changeSet>
更多XSD可参考
<!-- Children for changeSet -->
<xsd:group name="changeSetChildren">
<xsd:choice>
<xsd:element ref="comment" maxOccurs="1" />
<xsd:element ref="createTable" maxOccurs="unbounded" />
<xsd:element ref="dropTable" maxOccurs="unbounded" />
<xsd:element ref="createView" maxOccurs="unbounded" />
<xsd:element ref="renameView" maxOccurs="unbounded" />
<xsd:element ref="dropView" maxOccurs="unbounded" />
<xsd:element ref="insert" maxOccurs="unbounded" />
<xsd:element ref="addColumn" maxOccurs="unbounded" />
<xsd:element ref="sql" maxOccurs="unbounded" />
<xsd:element ref="createProcedure" maxOccurs="unbounded" />
<xsd:element ref="dropProcedure" maxOccurs="unbounded" />
<xsd:element ref="sqlFile" maxOccurs="unbounded" />
<xsd:element ref="renameTable" maxOccurs="unbounded" />
<xsd:element ref="renameColumn" maxOccurs="unbounded" />
<xsd:element ref="dropColumn" maxOccurs="unbounded" />
<xsd:element ref="mergeColumns" maxOccurs="unbounded" />
<xsd:element ref="modifyDataType" maxOccurs="unbounded" />
<xsd:element ref="createSequence" maxOccurs="unbounded" />
<xsd:element ref="alterSequence" maxOccurs="unbounded" />
<xsd:element ref="dropSequence" maxOccurs="unbounded" />
<xsd:element ref="renameSequence" maxOccurs="unbounded" />
<xsd:element ref="createIndex" maxOccurs="unbounded" />
<xsd:element ref="dropIndex" maxOccurs="unbounded" />
<xsd:element ref="addNotNullConstraint" maxOccurs="unbounded" />
<xsd:element ref="dropNotNullConstraint" maxOccurs="unbounded" />
<xsd:element ref="addForeignKeyConstraint" maxOccurs="unbounded" />
<xsd:element ref="dropForeignKeyConstraint"
maxOccurs="unbounded" />
<xsd:element ref="dropAllForeignKeyConstraints"
maxOccurs="unbounded" />
<xsd:element ref="addPrimaryKey" maxOccurs="unbounded" />
<xsd:element ref="dropPrimaryKey" maxOccurs="unbounded" />
<xsd:element ref="addLookupTable" maxOccurs="unbounded" />
<xsd:element ref="addAutoIncrement" maxOccurs="unbounded" />
<xsd:element ref="addDefaultValue" maxOccurs="unbounded" />
<xsd:element ref="dropDefaultValue" maxOccurs="unbounded" />
<xsd:element ref="addUniqueConstraint" maxOccurs="unbounded" />
<xsd:element ref="dropUniqueConstraint" maxOccurs="unbounded" />
<xsd:element ref="setTableRemarks" maxOccurs="unbounded" />
<xsd:element ref="setColumnRemarks" maxOccurs="unbounded" />
<xsd:element ref="customChange" maxOccurs="unbounded" />
<xsd:element ref="update" maxOccurs="unbounded" />
<xsd:element ref="delete" maxOccurs="unbounded" />
<xsd:element ref="loadData" maxOccurs="unbounded" />
<xsd:element ref="loadUpdateData" maxOccurs="unbounded" />
<xsd:element ref="executeCommand" maxOccurs="unbounded" />
<xsd:element ref="stop" maxOccurs="unbounded" />
<xsd:element ref="output" maxOccurs="unbounded" />
<xsd:element ref="empty" maxOccurs="unbounded" />
<xsd:element ref="rollback" maxOccurs="1" />
<xsd:any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded" />
</xsd:choice>
</xsd:group>
properties-maven-plugin 插件的集成使用
配置properties-maven-plugin
,使maven加载外部属性配置文件
<build>
<plugins>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>4.4.3</version>
<configuration>
<!--引用liquibase.properties配置文件-->
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<!--执行类型-->
<goal>update</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
liquibase.properties
配置如下:
changeLogFile: db_changelog/changelog-master.yaml
url: jdbc:mysql://localhost:3306/liquibase?serverTimezone=UTC
driver=com.mysql.cj.jdbc.Driver
# classpath=/path/to/classes
username: root
password:
1、需要通过dependency引入依赖jar包
liquibase-maven-plugin
,插件版本号与liquibase
版本号一致2、通过phase参数指定何时运行,一般为
process-resources
3、changeLogFile参数指定liquibase数据库变更日志文件
4、driver、url、username、password 配置数据库连接参数
数据库版本控制
更新版本
# 可在pom文件中指定版本标签,执行命令会自动进行更改
mvn clean package liquibase:update
# 也可命令行指定,还可以自己添加
mvn clean package liquibase:update -Dliquibase.tag=v3.0
添加版本标签
每次版本升级,就打上一个标签,如V1.0
、V2.0
等,如果有问题,就回滚至对应标签(版本)
# 命令行方式
mvn liquibase:tag -Dliquibase.tag=V1.1
maven配置方式:在maven中配置后执行以上更新语句会自动添加标签
<execution>
<phase>process-resources</phase>
<configuration>
<!--版本指定,也可在命令执行时指定-->
<tag>V1.1</tag>
</configuration>
<goals>
<!--执行类型-->
<goal>update</goal>
<goal>tag</goal>
</goals>
</execution>
版本回滚
LiquiBase
提供了按数量、日期和标签回滚的能力,如下:
# 按数量回滚,2表示回滚两个changeset
mvn liquibase:rollback -Dliquibase.rollbackCount=2
# 按日期回滚
mvn liquibase:rollback -Dliquibase.rollbackDate="2021-09-16 09:09:34"
# 按标签回滚
mvn liquibase:rollback -Dliquibase.rollbackTag=V1.0
生成回滚的sql脚本:
mvn liquibase:rollbackSQL -Dliquibase.rollbackTag=v1.0
mvn liquibase:rollbackSQL -Dliquibase.rollbackDate="2021-09-16 09:09:34"
生成变更日志
对于已有项目且之前未使用过Liquibase,使用 generateChangeLog
捕获数据库的当前状态,然后将这些更改应用于数据库。提供的扩展名决定了变更日志的格式,可为YAML
或JSON
或SQL
或XML
格式。
mvn liquibase:generateChangeLog
-Dliquibase.outputChangeLogFile=changelog-test.xml
**注意:**如果生成 SQL 格式的更改日志,请将目标数据库的类型名称指定为文件名的一部分,如
changelog.<db_type>.sql
对比差异
diff
允许您将相同类型或不同类型的两个数据库相互比较。
运行diff
目标需要两个 URL:
- referenceURL – 比较的来源。该
referenceURL
属性代表您的源数据库。 - URL – 比较的目标。该
url
属性代表您要与源数据库进行比较的目标数据库。
mvn liquibase:diff
-Dliquibase.changeLogFile=myChangeLog.xml
-Dliquibase.driver=oracle.jdbc.OracleDriver
-Dliquibase.url="jdbc:oracle:thin:@<IP OR HOSTNAME>:<PORT>:<SERVICE NAME OR SID>"
-Dliquibase.username=<USERNAME>
-Dliquibase.password=<PASSWORD>
-Dliquibase.referenceUrl="jdbc:oracle:thin:@<IP OR HOSTNAME>:<PORT>:<SERVICE NAME OR SID>"
-Dliquibase.referenceUsername=<USERNAME>
-Dliquibase.referencePassword=<PASSWORD>
生成将源数据库与目标数据库进行比较后应用更改的更改日志
mvn liquibase:diff -Dliquibase.diffChangeLogFile=mydiff.xml
Liquibase允许您使用diffTypes
属性来过滤要比较的对象类型。可以将多个过滤器作为逗号分隔列表添加到属性中。如果没有diffTypes
指定,则考虑所有对象。
mvn liquibase:diff -Dliquibase.diffTypes=tables,indexes,views
更多maven命令可查看:https://docs.liquibase.com/tools-integrations/maven/commands/home.html
liquibase 命令附录
更多命令可查看官方文档:https://docsstage.liquibase.com/commands/home.html
命令名称 | 命令描述 |
---|---|
update | 更新数据库到当前版本 |
updateSQL | 写入SQL将数据库更新到currentversion或STDOUT |
updateCount | 将本地num个未执行的changeset更改应用到数据库 |
updateCountSQL | 将本地num个未执行的changeset输出到sql文件 |
updateToTag | 更新数据库到指定tag的changeset |
updateToTagSQL | 更新数据库到指定tag的changeset输出到sql文件 |
rollback | 将数据库回滚到指定标签的状态 |
rollbackSQL | 将数据库回滚到指定标签的状态的sql |
rollbackToDate <date/time> | 将数据库回滚到给定日期/时间的状态。日期格式为YYYY-MM-DD HH:MM:SS 或YYYY-MM-DD'T'HH:MM:SS ,但可以仅指示日期或时间。 |
rollbackToDateSQL <date/time> | 写入SQL以将数据库回滚到给定日期/时间版本的状态到STDOUT |
rollbackCount | 回滚最近num个changeset |
rollbackCountSQL | 回滚最近num个changeset输出到sql |
futureRollbackSQL | 执行rollback标签里边的sql |
futureRollbackSQL | 输出rollback里边的sql到sql文件 |
futureRollbackFromTagSQL | 输出指定tag的回滚sql |
updateTestingRollback | 回滚更新数据库,然后再次回滚更改。用于测试回滚支持 |
generateChangeLog | 写入更改日志XML以将数据库的当前状态复制到标准输出 |
snapshot | 将数据库的当前状态写入标准输出 |
snapshotReference | 将referenceUrl数据库的当前状态写入标准输出 |
Diff Commands | 数据库对比命令 |
diff [diff parameters] | 数据库对比命令 |
diffChangeLog [diff parameters] | 数据库对比日志 |
Documentation Commands | 生成文档命令 |
dbDoc | 基于当前数据库和更改日志生成类似javadoc的文档 |
Maintenance Commands | 维护命令 |
tag | 给当前的数据库打标签,(只会打最新的一条记录的tag) |
tagExists | 检查对应的标签是否存在 |
status [–verbose] | 输出为执行changeset的行数 |
unexpectedChangeSets[–verbose] | 输出本地不存在changeset 行数 |
validate | 检查是否有错误的changelog |
calculateCheckSum | 检查指定changeset id 的checksum值 格式为 filepath::id::author |
clearCheckSums | 从数据库日志中删除所有保存的校验和 |
changelogSync | 标记所有的更改已执行 |
changelogSyncSQL | 生成标记更改已执行的sql并输出到标准输出 |
markNextChangeSetRan | 将下一个变更标记为已执行 |
markNextChangeSetRanSQL | 生成将下一个变更标记为已执行的sql并输出到标准输出 |
listLocks | 列出liquibase数据库锁 |
releaseLocks | 释放所有的liquibase数据库锁 |
dropAll | 删除数据库表(慎用!) |