一直以来,部门内部对于数据库结构的变更跟踪都处于一种切肤之痛,却又无暇顾及的状态。

0. 目录

  • 1. 概述
  • 2. 使用
    • 2.1 SpringBoot
    • 2.2 Maven Plugin
    • 2.3 命令行
    • 2.4 WEB Servlet
    • 2.5 spring
  • 3. changeset
  • 4. 最佳实践
  • 5. 参考

1. 概述

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

本文主要关注平时在liquibase使用过程中经常会遇到的一些需求和相应的对策,尝试提供一站式解决方案。

2. 使用

从官方提供的文档 可以看出,liquibase提供了多种使用方式,例如Ant,CommandLine,Maven Plugin等等。下面将挑选比较常用的来进行说明,方便读者快速入门。

2.1 SpringBoot

本文主要受众是研发人员,因此这里将与SpringBoot的集成放在首位。

其实liquibase与SpringBoot的集成可谓相当简单,因为SpringBoot的AutoConfig特性内置了对其的支持。

pom.xml

<dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId>
</dependency>

application.yml

spring:liquibase: # 显式启用enabled: true # 配置文件的路径,默认值为 classpath:/db/changelog/db.changelog-master.yaml# 这是总配置文件change-log: classpath:/db/changelog/db.changelog-master.xml

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/dbchangeloghttp://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"><!-- <includeAll path="classpath:liquibase/changelog" />-->             <!--  以下排列順序就是執行順序 --><!-- 至于sample-dsl-xml-table.xml中的内容,留待下面专门的小节进行专门讲解 --><include file="classpath:liquibase/changelog/sample-dsl-xml-table.xml"/><include file="classpath:liquibase/changelog/sample-dsl-xml-column.xml"/><include file="classpath:liquibase/changelog/sample-dsl-xml-data.xml"/>
</databaseChangeLog>

以上两步就算是完成了liquibase与SpringBoot的集成。

一些源码细节:

  1. LiquibaseAutoConfiguration。SpringBoot中对于liquibase的自动化配置入口。其中的SpringLiquibase 实现了 InitializingBean接口。
  2. LiquibaseProperties。可配置属性项的集散地。

参考链接:

  1. 官方文档 - SpringBoot集成
  2. 一起来学SpringBoot | 第二十四篇:数据库管理与迁移(Liquibase)
2.2 Maven Plugin

以笔者个人的经验,使用到Maven Plugin的时候主要是单独性地测试changesets,进行数据库对比,以及对以存在的数据库进行逆向,将其纳入版本控制中。

  1. 引入Maven Plugin

    <plugin><groupId>org.liquibase</groupId><artifactId>liquibase-maven-plugin</artifactId><version>3.4.2</version><configuration><changeLogFile>src/test/resources/liquibase/changelog/sample-dsl-xml-table.xml</changeLogFile><driver>com.mysql.jdbc.Driver</driver><url>jdbc:mysql://81.xx.xxx.xx:3306/xxxxx</url><username>root</username><password>123456</password><!--配置参数,以禁用弹出的对话框,该对话框将确认非本地数据库上的迁移 --><promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>                   </configuration><executions><execution><phase>process-resources</phase><goals><goal>update</goal></goals></execution></executions>
    </plugin>
    
  2. 常用的Maven Plugin Commands:

    # 执行某个changelog
    mvn liquibase:update -Dliquibase.changeLogFile=xxxx.xml# 对比两个数据库结构, 最终结果存放在指定位置. 注意最终的结果反映的是由源数据库结构变成目标数据库结构(由referenceUrl指示), 需要作出哪些变化.
    mvn liquibase:diff  '-Dliquibase.referenceUrl=jdbc:mysql://81.xx.xxx.xxx:3307/xxx' '-Dliquibase.referenceUsername=root' '-Dliquibase.referencePassword=123456' '-Dliquibase.diffChangeLogFile=D:/111.xml'# 逆向工程 - 生成当前数据库的changeset, 默认是生成数据库结构, 不包含数据
    mvn liquibase:generateChangeLog
    # 逆向工程 - 生成当前数据库的changeset, 只包含数据; diffTypes的可选值可参照文档(文档的生成参见下方命令)
    mvn liquibase:generateChangeLog '-Dliquibase.diffTypes="data"'# 生成数据库结构文档
    # 生成的文档默认位于target/liquibase/dbDoc目录,入口文件为其中的index.html。mvn liquibase:dbDoc# 获取liquibase-maven-plugin的完整帮助文档
    mvn help:describe '-DgroupId=org.liquibase' '-DartifactId=liquibase-maven-plugin' '-Dversion=3.4.2' '-Dfull=true'
    

参考链接:

  1. 官方文档 - Maven Plugin集成
2.3 命令行

数据库的版本控制的受众不仅仅是研发类岗位,对此liquibase给出的解决方案是 CLI工具。

  1. 安装。
    首先从 liquibase CLI下载地址 下载相应操作系统版本的liquibase二进制包,笔者这里下载的是 Liquibase 4.1.0-Windows-20200928

    # 如果本地下载太慢,笔者的解决方案是找个云服务器(例如腾讯云),在上面下载完之后拉取到本地。
    wget -c https://github.com/liquibase/liquibase/releases/download/v4.1.0/liquibase-4.1.0.zip
    

    这里千万别想当然地以为是我们通过Maven方式引入的那个liquibase-core-3.8.8.jar。虽然两者的内部结构是一致的,但 Liquibase 4.1.0-Windows-20200928中不仅仅包含liquibase.jar,还附带了相应的JAR依赖,以及一组示例代码等。

  2. 配置。

    # 1. 下载的liquibase-4.1.0.zip解压到任意目录,并配置相应的环境变量Path。(笔者有强迫症,这里就以powershell下为例)
    $Env:path=$Env:Path+";D:\liquibase-4.1.0"  # 获取完整的文档信息
    liquibase --help
    
  3. 示例。

    ################################ 准备工作
    # 这里我们假设:
    #   1. 操作目录:C:\Users\{User}\Desktop\liquibase\
    #   2. liquibase-4.1.0-bin目录:D:\liquibase-4.1.0\
    # 将 liquibase.properties , changelog-dsl-xml-table.xml, mysql-connector-java-8.0.13.jar 放置到 C:\Users\{User}\Desktop\liquibase\ 下。# liquibase.properties中的内容driver: com.mysql.jdbc.Driverclasspath: ./mysql-connector-java-8.0.13.jarurl: jdbc:mysql://81.68.158.66:3307/kqauth?useUnicode=true&characterEncoding=UTF-8username: rootpassword: 123456    # 打开powershell, 切换到操作目录
    cd C:\Users\{User}\Desktop\liquibase\################################ 常用操作
    # dbDoc : 生成数据库结构文档 ( 经过简单测试:changeLogFile参数对生成的文档没有影响,但又必须要 )
    java -jar D:\liquibase-4.1.0\liquibase.jar dbDoc D:/liquibase/ --logLevel=error --changeLogFile=changelog-dsl-xml-table.xml# update : 执行某个changelog
    java -jar D:\liquibase-4.1.0\liquibase.jar --changeLogFile=changelog-dsl-xml-table.xml update# 逆向工程 - 生成当前数据库的changeset, 默认是生成数据库结构, 不包含数据
    java -jar D:\liquibase-4.1.0\liquibase.jar --changeLogFile=generateChangeLog.xml generateChangeLog
    # 逆向工程 - 生成当前数据库的changeset, 只包含数据; diffTypes的可选值可参照文档.
    java -jar D:\liquibase-4.1.0\liquibase.jar --changeLogFile=generateChangeLog-data.xml  --diffTypes="data" generateChangeLog# 对比两个数据库结构, 最终结果存放在指定位置.
    # 注意最终的结果反映的是由源数据库结构变成目标数据库结构(由referenceUrl指示), 需要作出哪些变化.
    java -jar D:\liquibase-4.1.0\liquibase.jar --referenceUrl=jdbc:mysql://81.68.158.66:3306/kqauth --referenceUsername=root --referencePassword=123456 --changeLogFile=D:/111.xml --diffTypes="data" diff
    

参考链接:

  1. 官方文档 - CLI集成
  2. Installing Liquibase Command Line for Windows
2.4 WEB Servlet

直接参考官方文档 - servlet-listener。

2.5 spring

对于一些历史项目,还是以spring为主的,这里提供两个参考链接:

  1. [Liquibase]集成liquibase的两种形式
  2. Liquibase+spring 初步使用

3. changeset

我们平时会使用到的主要分为两类格式 sql和xml。

文件格式 优点 缺点 参考
sql 复用SQL知识。 缺少提示,数据库强相关。 官方文档 - sql-format
xml 1. 数据库无关。
2. 有XSD(智能提示和校验)。
1. 一定的学习曲线。但在XSD提供的智能提示以及XML标签的良好命名规范下,相信这些都不会是主要障碍。 官方文档 - xml-format
  1. SQL

    <!-- 基于SQL语句 -->
    <changeSet id="createTable" author="fulizhe"><sql>create table users ( id int primary key not null , name varchar(20) )</sql><sql>insert into users ( id, name ) values (1, 'fulizhe')      </sql>
    </changeSet><!-- 基于SQL文件 -->
    <changeSet id="6" author="joe"> <sqlFile path="insert-distributor-data.sql"/>
    </changeSet>
    
  2. 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"><!-- office document : https://docs.liquibase.com/concepts/basic/xml-format.html --><!-- ################### 统一配置属性, 供之后使用 ################### --><property name="now" value="now()" dbms="mysql" /><!-- 不同的数据库, 不同的配置 ( https://docs.liquibase.com/concepts/basic/changelog-parameters.html --><property name="clob.type" value="clob" dbms="oracle,postgresql"/> <property  name="clob.type" value="longtext" dbms="mysql"/> <!-- 基于XML, 这种方式与数据库无关, 迁移性强; 有XSD提示; 但需要熟悉其语法 --><!-- ################### Table相关 ################### --><!-- 创建表 --><changeSet id="addTable" author="fulizhe"><!-- preConditions --> <preConditions onFail="MARK_RAN"><not><tableExists tableName="tb2_member" /></not></preConditions><createTable tableName="tb2_member"><column name="id" type="bigint" autoIncrement="true" remarks="主键"><constraints primaryKey="true" nullable="false" /></column>    <column name="mobile" type="varchar(50)" remarks="手机号"><constraints nullable="false" /></column></createTable><!-- LookupTable --><addLookupTable existingTableName="tb2_member" existingColumnName="mobile" newTableName="tb2_member_COPY" newColumnName="mobile" />   </changeSet><!-- 删除表 --><changeSet id="dropTable" author="fulizhe"><preConditions><tableExists tableName="tb2_member" /></preConditions><dropTable tableName="tb2_member" /></changeSet><!-- 修改表名 --><changeSet id="renameTable" author="fulizhe"><preConditions><tableExists tableName="tb2_member" /></preConditions><renameTable oldTableName="tb2_member"newTableName="tb2_member2"/> </changeSet>     <!-- 请注意,这一条在liquibase4.1.0是没有的,虽然官方文档里确实有这个。https://docs.liquibase.com/change-types/community/set-table-remarks.html <changeSet id="setTableRemarks" author="fulizhe"><preConditions><tableExists tableName="tb2_member2" /></preConditions><setTableRemarks remarks="this is a remark by liquibase"  tableName="tb2_member2"/>  </changeSet>--><!-- ################### Column相关 ################### --><!-- 添加字段 --><changeSet id="addColumn" author="WATER" context="add-column"><preConditions> <tableExists tableName="tb2_member" /> </preConditions><addColumn tableName="tb2_member"><column name="nick_name" type="varchar(10)" remarks="昵称"></column></addColumn></changeSet>   <changeSet id="modifyColumn" author="WATER" context="add-column"><preConditions> <tableExists tableName="tb2_member" /> </preConditions>    <!-- 修改字段名称( 其实可以连带类型一起修改了 ) --><renameColumn tableName="tb2_member" oldColumnName="nick_name"newColumnName="nick_name_new" columnDataType="varchar(20)"/><!-- 修改字段类型 ( https://blog.csdn.net/m0_38105216/article/details/83896599 ) --><modifyDataType tableName="tb2_member" columnName="nick_name_new" newDataType="varchar(20)" /><!-- 设置Column注释, 和上面的Table类似,没有提供 <setColumnRemarks  columnName="nick_name_new"  remarks="A String"  tableName="tb2_member"/>     --><!-- 将一个已经存在的Column修改为自增Column --><addAutoIncrementcolumnDataType="int"columnName="id" incrementBy="2"  startWith="100"  tableName="tb2_member"/>                </changeSet><!-- ################### Index相关 ################### --><createIndex indexName="idx_mobile"  tableName="tb2_member"  unique="true">  <column  name="mobile"/>  </createIndex>       <dropIndex indexName="idx_mobile"         tableName="tb2_member"/>  <!-- ################### 增删改查 ################### --><insertdbms="!h2"  tableName="tb2_member">  <column  name="mobile"  value="132"/>  </insert><update  tableName="tb2_member"><column name="mobile" value="address value"/><where>id=100</where></update>        <delete  tableName="tb2_member">  <where>id=100</where>  </delete>   <!-- OtherloadData: Loads data from a CSV file into an existing table when you add it to your changelog.loadUpdateData: Loads or updates data from a CSV file into an existing table. mergeColumns: Concatenates the values in two columns and joins them with a string, and stores the resulting value in a new column.executeCommand: Executes a system command. <executeCommand  executable="mysqldump"  os="Windows 7"  timeout="10s">  <arg  value="-out"/>  <arg  value="-param2"/>  </executeCommand>     stop: Stops Liquibase execution with a message. Mainly useful for debugging and stepping through a changelog<stop  message="What just happened???"/> output: Logs a message and continues execution. 类似于日志系统, 注意这个在CLI中并没有出现. <output  target="STDERR">Make sure you feed the cat</output>  customChange: creates a custom Change Type class.通过该标签,用户将拥有针对数据库的完全自主权,用户可以按照自己的需求应对数据库的变更逻辑。 -->
    </databaseChangeLog>

参考链接:

  1. 官方文档 - change-types 其中按照被修改的对象进行了分类。
  2. 官方文档 - Basic Concepts

4. 最佳实践

这里直接借用网上资料,具体出处找不到了:

  1. ChangeSet ID 建议使用:
    a. Flayway的命名格式V<version>[_<SEQ>][__description],如V1.0_0__init
    b. [任务ID]-[日期]-[序号],如T100-20190705-001
  2. ChangeSet 必须填写author。
  3. liquibase禁止对业务数据进行SQL操作。
  4. 使用<sql>的时候,禁止包含schema名称。
  5. liquibase禁止使用存储过程。
  6. 所有表,列都加remarks进行注释。
  7. 若脚本有变动,勿直接对脚本进行修改,添加修改脚本并引入。尤其是对于已经提交近SCM的脚本。
  8. 不要随意升级liquibase,特别是大版本升级。不同版本ChangeSet MD5SUM的算法不一样。

5. 参考

  1. liquibase - GitHub
  2. Liquibase使用小结
  3. 使用liquibase-maven-plugin实现持续数据库集成 这个不错!
  4. One-Stop Guide to Database Migration with Liquibase and Spring Boot

liquibase常见操作相关推荐

  1. 路径,文件,目录,I/O常见操作汇总

    摘要:    文件操作是程序中非常基础和重要的内容,而路径.文件.目录以及I/O都是在进行文件操作时的常见主题,这里想把这些常见的问题作个总结,对于每个问题,尽量提供一些解决方案,即使没有你想要的答案 ...

  2. python字典操作添加_Python字典常见操作实例小结【定义、添加、删除、遍历】

    本文实例总结了python字典常见操作.分享给大家供大家参考,具体如下: 简单的字典: 字典就是键值对key-value组合. #字典 键值对组合 alien_0 ={'color':'green', ...

  3. BOM,DOM常见操作和DHML

    BOM (Browser Object Model)浏览器对象模型,控制浏览器的一些行为 window对象 代表一个HTML文档 属性 页面导航的5个属性 self, parent, top, ope ...

  4. go语言笔记——切片函数常见操作,增删改查和搜索、排序

    7.6.6 搜索及排序切片和数组 标准库提供了 sort 包来实现常见的搜索和排序操作.您可以使用 sort 包中的函数 func Ints(a []int) 来实现对 int 类型的切片排序.例如  ...

  5. 在单链表写入一组数据代码_链表常见操作和15道常见面试题

    什么是单链表 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer),简单来说链表并不像数组那样 ...

  6. python基础实例-Python基础之字符串常见操作经典实例详解

    本文实例讲述了Python基础之字符串常见操作.分享给大家供大家参考,具体如下: 字符串基本操作 切片 # str[beg:end] # (下标从 0 开始)从下标为beg开始算起,切取到下标为 en ...

  7. C#路径/文件/目录/I/O常见操作汇总(一)

    文件操作是程序中非常基础和重要的内容,而路径.文件.目录以及I/O都是在进行文件操作时的常见主题,这里想把这些常见的问题作个总结,对于每个问题, 尽量提供一些解决方案,即使没有你想要的答案,也希望能提 ...

  8. python下selenium模拟浏览器常见操作

    本文主要记录下selenium的常见操作,如定位具体元素的不同方法.在具体元素内循环.提取文本等.具体代码如下: # -*- coding: utf-8 -*- ''' Created on 2019 ...

  9. Java数组常见操作

    Java数组常见操作 文章目录 Java数组常见操作 7.0 数组的遍历 1.使用foreach循环访问数组中每个元素. 2.使用简单的for循环(多层循环嵌套)来遍历数组. 7.1 数组长度 7.2 ...

最新文章

  1. 多线程并发的解决方案 volatile synchronized notify notifyAll wait关键字分析
  2. bit_length
  3. SAP CRM有哪些版本
  4. HTTP管线化(HTTP pipelining)
  5. dubbo的监控中心
  6. JavaSE面向对象-笔记
  7. Hibernate关系映射(三) 多对一和一对多
  8. Spring框架学习---Spring Framework上篇
  9. Oracle定时任务dbms_job使用详解
  10. 树莓派小车————全部代码
  11. DQN 强化学习 (Reinforcement Learning)
  12. Hbuilder 连接夜神模拟器
  13. 《计算机组成原理》第五章指令系统 部分课后习题答案 清华大学出版_秦磊华_谭志虎
  14. 2021年起重机械指挥考试题及起重机械指挥模拟考试
  15. 2019纪中寒假培训
  16. 前端js 下载xls表格
  17. 基于AT91RM9200与LINUX2.6.26内核的嵌入式平台开发全过程
  18. Adaptive Graph Completion Based IncompleteMulti-View Clustering(2020)
  19. 【陈工笔记】# ubuntu系统登陆密码忘记,如何修改 #
  20. Windows 10 PE的程序包

热门文章

  1. 计算机工程改通讯作者,我中心3篇论文被AAAI2020录用
  2. 怎样才能成为办公室里最有效率的人
  3. vue项目实现屏幕自适应
  4. Persistence provider caller does not implement the EJB3 spec correctly. Pers
  5. onscroll的用法
  6. JS 滚轮事件 onscroll - Kaiqisan
  7. MySQL-基础-DDL语句(一)-数据库的操作
  8. 产品分享:Qt+Arm基于RV1126平台的内窥镜软硬整套解决方案(实时影像、冻结、拍照、录像、背光调整、硬件光源调整,其他产品也可使用该平台,如视频监控,物联网产品等等)
  9. 方舟生存进化服务器不稳定,win10玩方舟生存进化游戏一进服务器就自动闪退如何解决...
  10. uniapp支付功能实现