Liquibase简介及与Spring Boot的集成使用

首发地址,欢迎查看:https://www.pengtao.vip/archives/liquibasejianjiejispringbootjichengshiyong

Liquibase是什么

Liquibase 是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制。

Liquibase能干嘛

  • 不依赖于特定的数据库,目前支持包括 Oracle/SqlServer/DB2/MySql/Sybase/PostgreSQL 等几十种数据库,这样在数据库的部署和升级环节可帮助应用系统支持多数据库。
  • 提供数据库比较功能,比较结果保存在XML中,基于该XML你可用 Liquibase 轻松部署或升级数据库。
  • 以XML存储数据库变化,其中以authorid唯一标识一个更改集ChangeSet,支持数据库变化的合并,因此支持多开发人员同时工作。
  • 在数据库中保存数据库修改历史(DatabaseChangeHistory),在数据库升级时自动跳过已应用的更改集。
  • 提供变化应用的回滚功能,可按时间、数量或标签(tag)回滚已应用的更改集。通过这种方式,开发人员可轻易的还原数据库在任何时间点的状态。
  • 可生成数据库修改文档(HTML格式)
  • 提供数据重构的独立的IDE和Eclipse插件。

基本概念

使用 Liquibase时,可以使用 Liquibase 函数SQL 定义更改。重要的是,这些模式不是互斥的,可以结合使用,从而在如何定义和部署数据库更改方面提供了相当大的灵活性。对于使用 Liquibase 函数定义的更改,Liquibase生成适合目标数据库的SQL。这在下列场景是很有用的:

  • 支持多个不同的数据库后端。
  • 使不熟悉 SQL 或不熟悉 SQL 的开发人员能够定义数据库更改。数据库迁移可以在 XMLJSONYAML 中定义,而不是 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文件中按照顺序出现的changeSetinclude标签。

ChangeSet标签

changeSetauthorid属性以及changelog文件的位置唯一标识,是 Liquibase 跟踪执行的单位。运行 Liquibase 时,它会查询标记为已执行的changeSetDATABASECHANGELOG 表,然后执行更改日志文件中尚未执行的所有changeSet

changeSet作为一次变更的单位,可以是新建一张表、加一列,插入数据、删除索引等。升级与回滚都是以changeset为单位的;每个changeset会通过idauthor来标记。

多环境动态标识替换:

不同数据库字段标识是不一样的,语法也会有不同,通过定义属性,能解决这个问题

<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,当回滚后,就会删去被回滚掉的记录。

  • 版本回滚 可以使用命令行 或者 mavenant 等构建工具来完成。

<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>

启动项目,可以发现在数据库下已经创建了相应的表,可以看到数据库现在额外创建了另外两个表:databasechangelogdatabasechangeloglock

  • 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.0V2.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 捕获数据库的当前状态,然后将这些更改应用于数据库。提供的扩展名决定了变更日志的格式,可为YAMLJSONSQLXML格式。

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:SSYYYY-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删除数据库表(慎用!)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值