Liquibase学习4 - 管理changelog

文章目录

    • Changelog
      • 不同格式类型的Changelog能力支持
      • 更改类型:ChangeType(由Liquibase定义的DDL语句)
      • changeSet
        • changeSet节点的属性
          • 概述
          • labels - 标签名、组名 - 有部署权限建议使用这个
          • context - 上下文 - 无部署权限的建议使用这个
          • runOnChange - 变更集changeset节点内容修改时是否重新执行
          • runAlways - 每次部署该changeset节点都会运行,不管之前是否以部署过
          • runOrder - 当前changeset节点放置在开头或者最后执行
        • changeSet的子节点
          • preConditions
            • preConditions的属性
            • preConditions所有支持的子节点查看
            • 子节点:changeSetExecuted
            • 子节点:sqlCheck
      • 最佳实践
        • changelog文件如何拆分更好的管理
          • 划分-版本号
          • 划分-功能模块
          • 划分-功能模块+功能模块结合
        • changelog太大且生产部署了多次,即将拆分重构changelog文件
          • 风险
          • 方式1 - 学会使用databaseChangeLog的logicalFilePath属性
          • 方式2 - 不管以前的changelog文件,从此时此刻前按组分规定的拆分规范进行组织changelog文件的引入
        • liquibase运行部署太慢
          • 可能原因
          • 优化
            • 优化1:删除不必要的changeset节点
            • 优化2:合并历史changset节点 - 学会使用validCheckSum节点或clear-checksums命令
        • 多模式(Schema)部署 - 即不同的数据库名

Changelog

不同格式类型的Changelog能力支持

Liquibase学习4 - 管理changelog_第1张图片

更改类型:ChangeType(由Liquibase定义的DDL语句)

官网: https://docs.liquibase.com/change-types/home.html

作用: 其实就是Liquibase定义的节点,让其同一种语句支持种数据库的部署,如使用liquibase定义的,不使用数据库本身的DDL语句CREATE TABLE ,因为这种DDL语句可能仅适用你当前所需部署的数据库,而不支持如mongoDB这些数据库,让官方定义的内部自动转成mongodDB支持的语句

changeSet

changeSet节点的属性

概述

全部的属性节点查看官网: https://docs.liquibase.com/concepts/changelogs/changelog-formats.html

Liquibase学习4 - 管理changelog_第2张图片

labels - 标签名、组名 - 有部署权限建议使用这个

特别注意: 复杂的匹配表达式逻辑是写在命令行参数–labels上,而changeSet节点的labels是不可以写表达式逻辑只能是 “标签名1,标签名2,标签名3” - 所以我就为什么说labels适合无部署权限的人使用


官网: https://docs.liquibase.com/concepts/changelogs/attributes/labels.html?Highlight=Labels

作用: 提供了对其变更集进行分组和分类的能力,以控制执行哪些变更集。在 Liquibase 执行期间,可以提供一个标签表达式,该表达式将充当过滤器,以精确控制将执行哪些变更集

使用0: 符合标签表达式的hangeSet节点才可以被liquibase部署运行
使用1: changeSet节点的属性labels定义当前变更节点所属于的标签名
使用2: iquibase update --labels=标签表达式 或者 liquibase update --labelFilter=标签表达式,用于说明什么标签名的结果集需要被执行。但如果–labels、–labelFilter不定义则默认全部执行,无需过滤操作

注意: --labelFilter这个参数最新的liquibase版本已经被剔除了,所以只用–labels即可

标签表达式逻辑语句
and
or或者逗号,
!或者not:否定,经测试linux好像用不了感叹号,一直报错,所以使用not即可
():分组,用于复杂的逻辑语句
标签表达式案例
not v1:不执行标签名为v1的changeSet节点
v1,v2 and v3 等价于 v1 or (v2 and v3)
//帮助文档
liquibase update --help

//符合的标签才进行部署的数据库中
liquibase update --label="标签表达式"

//最新版本--labelFilter已经不支持,不要使用
liquibase update --labelFilter="标签表达式"

讲解


<changeSet id="2" author="LinRuChang" labels="20220713,v1" >

        <comment>创建表user_20220713_v1comment>
        <sql>
            CREATE TABLE `user_20220713_v1`
            (
                `id`          char(32) CHARACTER SET utf8 COLLATE utf8_bin        NOT NULL COMMENT '主键',
                `name`        varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '角色名',
                PRIMARY KEY (`id`) USING BTREE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='liquibase测试表'
        sql>
        <rollback>
            <comment>删除表comment>
            <dropTable tableName="user_20220713_v1">dropTable>
        rollback>
    changeSet>

过滤节点讲解

# 仅部署执行 标签名【同时是v1和20220713的changeset节点】或者 【标签名不是v1的节点】或者 【没有设置labels属性的changeset节点】
liquibase update --labels="(v1 and 20220713) or (not v1)"


context - 上下文 - 无部署权限的建议使用这个

特别注意: 复杂的匹配表达式逻辑是写在changeSet节点的context属性上的,而命令行参数–labels上是不可以写表达式逻辑只能是 “上下文名1,上下文名2,上下文名3” 这种值格式 - 所以我就为什么说context适合有部署权限的人使用


官网: https://docs.liquibase.com/concepts/changelogs/attributes/contexts.html

作用: 提供了对其变更集进行分组和分类的能力,以控制执行哪些变更集。在 Liquibase 执行期间,可以提供一个上下文表达式,该表达式将充当过滤器,以精确控制将执行哪些变更集

使用0: 符合上下文表达式的hangeSet节点才可以被liquibase部署运行
使用1: changeSet节点的属性context定义当前变更节点所属于的上下文名
使用2: iquibase update --contexts=“上下文名1,上下文名2,上下文名3” ,用于说明什么上下文名的结果集需要被执行。但如果–contexts不定义则默认全部执行,无需过滤操作

上下文属性表达式逻辑语句
and
or或者逗号,
!或者not:否定,经测试linux好像用不了感叹号,一直报错,所以使用not即可
():分组,用于复杂的逻辑语句
上下文属性表达式案例
not v1:不执行标签名为v1的changeSet节点
v1,v2 and v3 等价于 v1 or (v2 and v3)
//帮助文档
liquibase update --help

//符合的标签才进行部署的数据库中
liquibase update --contexts="上下文名1,上下名2"

讲解

    
    <changeSet id="3" author="LinRuChang" context="20220713 and v2 and v2lrc" >
        <comment>创建表user_20220713_v2_v2lrccomment>
        <sql>
            CREATE TABLE `user_20220713_v2_v2lrc`
            (
                `id`          char(32) CHARACTER SET utf8 COLLATE utf8_bin        NOT NULL COMMENT '主键',
                `name`        varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '角色名',
                PRIMARY KEY (`id`) USING BTREE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='liquibase测试表'
        sql>
        <rollback>
            <comment>删除表comment>
            <dropTable tableName="user_20220713_v2_v2lrc">dropTable>
        rollback>
    changeSet>

    
    <changeSet id="5" author="LinRuChang" context="not v2" >
        <comment>创建表user_20220713_not_v2comment>
        <sql>
            CREATE TABLE `user_20220713_not_v2`
            (   
                `id`          char(32) CHARACTER SET utf8 COLLATE utf8_bin        NOT NULL COMMENT '主键',
                `name`        varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '角色名',
                PRIMARY KEY (`id`) USING BTREE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='liquibase测试表' 
        sql>
        <rollback>
            <comment>删除表comment>
            <dropTable tableName="user_20220713_not_v2">dropTable>
        rollback>
    changeSet>

    
    <changeSet id="4" author="LinRuChang" context="20220713 or v2 or v2lrc" >
        <comment>创建表user_20220713_v2_v2lrc_orcomment>
        <sql>
            CREATE TABLE `user_20220713_v2_v2lrc`
            (   
                `id`          char(32) CHARACTER SET utf8 COLLATE utf8_bin        NOT NULL COMMENT '主键',
                `name`        varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '角色名',
                PRIMARY KEY (`id`) USING BTREE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='liquibase测试表' 
        sql>
        <rollback>
            <comment>删除表comment>
            <dropTable tableName="user_20220713_v2_v2lrc">dropTable>
        rollback>
    changeSet>

过滤节点讲解

# 仅部署执行 上下文名是20220713或v1的以及没有定义context属性的changeset节点
liquibase update-sql --contexts="20220713,v1"

runOnChange - 变更集changeset节点内容修改时是否重新执行

官网: https://docs.liquibase.com/concepts/changelogs/attributes/runonchange.html

可能场景使用建议: 有些情况下存储过程(虽然不常用)的内容逻辑发生变更,可以定义使用该属性让其一旦内容跟发生变化则重新部署运行,而不需新起一个changeset节点部署运行

重新执行成功后: 在databasechangelog表根据ID、AUTHOR、FILENAME的值找到对应行记录修改其中的DATEEXECUTED、ORDEREXECUTED、EXECTYPE、MD5SUM、DEPLOYMENT_ID这几个列

默认
runOnChange值
false:检测到当前changset的md5发生变化,则抛出异常,终止liquibase部署运行,已经部署过得changeset节点不允许内容发生变化
true:每次liquibase检测到当前changeset的内容变更即MD5发生变化,则重新部署执行当前changeset节点

Liquibase学习4 - 管理changelog_第3张图片

runAlways - 每次部署该changeset节点都会运行,不管之前是否以部署过

官网: https://docs.liquibase.com/concepts/changelogs/changelog-formats.html?Highlight=runAlways

注意: 如果你需要每次部署的执行,且该changeset的部署内容会发生变更,请将runAlways、runOnChange都设置为true,否则一旦你内容变化,则会导致当前changset内容md5跟之前部署不一致,导致后续的liquibse节点部署失败

默认
runAlways值
false:如果之前有部署过即databasechangelog找到执行记录,则不会在执行该节点的部署内容
true:每次部署必执行,不管之前有没部署过

runOrder - 当前changeset节点放置在开头或者最后执行

小知识: 官方说一般配合runAlways使用,当然不配合也是可以

默认
runAlways值
空:按当前changset在当前changelog文件的内容顺序执行
first:不管changeset内容顺序,一开始就立即执行
last:不管changeset内容顺序,放置到最后执行

Liquibase学习4 - 管理changelog_第4张图片

changeSet的子节点

preConditions

官网: https://docs.liquibase.com/concepts/changelogs/preconditions.html

preConditions的属性
preConditions属性
onFail:先决条件得到的结果是false的情况下的处理方案
onError:先决条件执行的过程中发生异常情况下的处理方案
onFailMessage:先决条件为false时的日志信息
onErrorMessage:先决条件发生异常时的日志信息
onSqlOutput:这玩意看文档没看懂是干嘛的
默认值
建议都设置成这个
onFail的属性值:校验是false的情况
HALT:暂停整个更改日志的执行,项目直接抛出异常导致项目启动失败
CONTINUE:跳过变更集。下次更新时将再次尝试执行变更集。下次启动项目会尝试继续执行该changeSet节点
MARK_RAN:跳过变更集,但将其标记为已执行,下次启动项目不在执行该changeSet节点
WARN:发送警告并继续正常执行当前变更集,即是校验失败也继续执行changeSet节点中定义的SQL语句,依然可能会导致启动失败,如创表语句必失败,但修改表结构可能不会失败
默认值
建议都设置成这个
onError的属性值:校验语句发生异常的时候
HALT:暂停整个更改日志的执行,项目直接抛出异常导致项目启动失败
CONTINUE:跳过变更集。下次更新时将再次尝试执行变更集。下次启动项目会尝试继续执行该changeSet节点
MARK_RAN:跳过变更集,但将其标记为已执行,下次启动项目不在执行该changeSet节点
WARN:发送警告并继续正常执行变更集,即是校验失败也继续执行changeSet节点中定义的SQL语句,依然可能会导致启动失败,如创表语句必失败,但修改表结构可能不会失败
preConditions所有支持的子节点查看

官网: https://docs.liquibase.com/concepts/changelogs/preconditions.html?Highlight=changeSetExecuted

Liquibase学习4 - 管理changelog_第5张图片

子节点:changeSetExecuted

官网: https://docs.liquibase.com/concepts/changelogs/preconditions.html

作用: 指定的更改集是否已被执行。

<preConditions onFail="HALT">
    <changeSetExecuted id="1" author="liquibase" changelog-file="changelog.xml" />
preConditions>

Liquibase学习4 - 管理changelog_第6张图片

子节点:sqlCheck

官网: https://docs.liquibase.com/concepts/changelogs/preconditions.html

作用: 执行一个SQL字符串并检查返回值。SQL结果必须是单行单列的数据

<preConditions onFail="WARN">
    <sqlCheck expectedResult="1">
        SELECT COUNT(1) FROM pg_tables WHERE TABLENAME = 'myRequiredTable'
    sqlCheck>
preConditions>

Liquibase学习4 - 管理changelog_第7张图片

最佳实践

changelog文件如何拆分更好的管理

官方: https://learn.liquibase.com/unit/view/id:2661

注意: 划分的模块,使用 进行将所有切割changelog模块组织起来

拆分
第一种:以应用部署版本号令起一个changelog文件,如changelog-2.1.3.xml
第二种:以应用功能模块名令起一个changelog文件,如changelog-cert.xml
第三种:前面两种的结合,版本号是目录名,每个版本号下划分功能changelog文件
划分-版本号

Liquibase学习4 - 管理changelog_第8张图片

划分-功能模块

Liquibase学习4 - 管理changelog_第9张图片

划分-功能模块+功能模块结合

Liquibase学习4 - 管理changelog_第10张图片

changelog太大且生产部署了多次,即将拆分重构changelog文件

风险

文章: https://learn.liquibase.com/unit/view/id:2634

风险
1. 更新失败,因为没有识别变更集依赖关系
2. 校验和错误的发生是因为变更集在部署后被修改 - DATABASECHANGELOG表的MD5SUM
3. liquibase的逻辑主键是(id、author、FILENAME)组成,拆分肯定会导致文件名不一样,所以主键不一样,更新被重新部署到数据库
4. 环境会变得不同步,因为更改集在应用到管道中的所有数据库之前会被删除
方式1 - 学会使用databaseChangeLog的logicalFilePath属性

官网: https://docs.liquibase.com/concepts/changelogs/attributes/logicalfilepath.html?Highlight=logicalFilepath

方式2 - 不管以前的changelog文件,从此时此刻前按组分规定的拆分规范进行组织changelog文件的引入

意义: 由于拆分历史臃肿庞大的changelog文件,比较费时费力(要做足够多的测试),毕竟涉及到数据库的变更,历史的东西能不动就不动。但是如果你的changelog文件不是很臃肿,当然还是建议你按组内新的规范进行拆分为好,方便后续维护。

liquibase运行部署太慢

小贴士: 官方说自己的liquibase产品效率足够快,liquibase部署的慢很可能是使用者自身的问题

可能原因
效率慢原因
1. 某些changeset节点增加毫无必要的runAlways=true的设置,即每次部署都会执行该节点
2. 毫无必要的全局前置条件,changelog肯定会有做部署文件拆分,changelog1有全局前置条件(历史),但是新的部署内容在changelog2,这就导致每次部署必会运行changelog1的前置条件
3. 重建索引,可能你每次部署运行的时候,都要删除,在重建某个表的索引,增加表的查询效率,数据越多,键索引时间越久
优化
学会使用validCheckSum节点或clear-checksums命令
优化手段
1. 删除不必要的changeset节点
2. 合并changset节点
优化1:删除不必要的changeset节点

案例: 例如:一个changset节点是创表a,另一个是删除a,其实两者一合起来就是啥都没做,可以考虑将这两个changeset节点直接从xml删掉即可

优化2:合并历史changset节点 - 学会使用validCheckSum节点或clear-checksums命令

官网validCheckSum: https://docs.liquibase.com/concepts/changelogs/changelog-formats.html?Highlight=validCheckSum

官网clear-checksums: https://docs.liquibase.com/commands/maintenance/clear-checksums.html?Highlight=clear

案例: 例如changelog文件中有3个历史changeset节点,一个是创空表a,一个是在a中加字段B,一个是在a中加字段C,可以将这3个changeset合并一个changeset,即创表的时候就增加字段B、C即可

二选一
二选一
changeset节点合并步骤开始
在当前changelog文件中新启一个changeset节点,但是id、author属性字段必须跟其中一个待删的changset节点一致
2. 新节点内添加一个节点,内容是原先旧的id、author节点的md5值,自行使用calculate-checksum命令计算出来,或者直接从DATABASECHANGELOG表的对应行的MD5SUM复制过来
3. 运行 liquibase --changelogFIle=当前changeLog文件路径 clear-checksums,清空MD5SUM字段值
删除或注释掉旧的合并前的changeset节点

使用节点进行删除合并





使用clear-checksums命令进行删除合并 = 这个更简单

多模式(Schema)部署 - 即不同的数据库名

理念: 将不同的数据库名的单独作为一个xml管理,且设置context用来标记这个XML部署到哪个数据库的,最后liquibase update部署运行的时候需要指定 --contexts 采用哪个changelog文件运行 以及 -default-schema-name 或者 --default-catalog-name 指定部署的数据库名

iquibase.bat update --contexts="lrc_blog2" --defaultSchemaName="lrc_blog2"


lrc_blog1-changelog.xml


<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
        xmlns:pro="http://www.liquibase.org/xml/ns/pro"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
		http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd
		http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd
		http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd"
        context="lrc_blog3"
>

    <changeSet id="0" author="lrc" >
        <tagDatabase tag="blog3_version">tagDatabase>
    changeSet>

    <changeSet id="1" author="lrc" >
        <createTable tableName="user3">
            <column name="id" type="int" remarks="主键">
                <constraints primaryKey="true">constraints>
            column>
            <column name="year" type="int" remarks="年龄">column>
        createTable>
    changeSet>

databaseChangeLog>


你可能感兴趣的:(Liquibase,学习,数据库,linux,liquibase)