原文地址:【翻译】liquibase 中 change set 的格式
欢迎访问我的个人博客:http://blog.duhbb.com/
引言
平常提 liquibase 提的不多, 所以没有深度了解, 然后翻了一个字段重复的错误, 导致后面折腾了一下. 今天主要是学一下 liquibase 中的 change set 的格式, 内容来自官方文档, 链接附在了最后.
下面正文开始:
Changelog Formats
changeset 标签是 liquibase 对数据库执行变更的基本单元, 可以将数据库的各种 liquibase 变更类型组织到一起. 在一个 changelog 中会记录一系列的 changesets 以及其中包含的各种变更.
通过 id 属性 (author:id) 以及 changelog 所在的文件路径唯一标识了一个 changeset.id 标签仅仅用作标识符, 既不指定 changeset 的执行顺序, 也不一定得是一个整数. 如果你不知道或者不想保存实际的作者名字, 可以使用一个诸如 UNKNOWN
的占位符来指定. 为了执行 changeset, 你必须指定作者和 id.
<?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"
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-4.9.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-4.9.xsd">
<changeSet id="1" author="bob">
<comment>A sample change log</comment>
<createTable/>
</changeSet>
<changeSet id="2" author="bob" runAlways="true">
<alterTable/>
</changeSet>
<changeSet id="3" author="alice" failOnError="false" dbms="oracle">
<alterTable/>
</changeSet>
<changeSet id="4" author="alice" failOnError="false" dbms="! oracle">
<alterTable/>
</changeSet>
</databaseChangeLog>
运行 changeset
因为 liquibase 使用 DATABASECHANGELOG 这个表, 它会从 changelog 中按照顺序读取所有的 changesets, 对于每一个 changeset, 根据 id/author/filetpath
的组合查询这个 changeset 是否被执行过了.
如果这个 changeset 在数据库中被标记为已经执行了, 那么这个 changeset 就会被跳过, 除非有一个 runAlways
的属性设置为 true, 这个已经执行的 changeset 会被重新执行.changeset 中的所有 change 都执行完成之后,liquibase 将会在 DATABASECHANGELOG 中插入一条新的记录,id/author/filepath
以及这个 changeset 的 MD5Sum.
filepath 是一个路径, 用于定义 changelog-file 这个属性. 即使是同一个文件可以使用不同的路径引用, 除非使用了 logical-file-path, 否则还是被认为是不同的文件.
liquibase 试图在事务中执行每个 changeset, 执行成功则提交, 失败则回滚. 有些数据库会自动的提交事务, 可能导致意想不到的问题. 因此, 最佳实践是每个 changeset 中只有一个变更, 除非你想在事务中执行一组非自动提交的变更, 比如插入多个数据.
可用的属性
属性 | 解释 |
---|---|
id | 指定一个字母-数字格式的标识符, 这个是必须的. 注意, 如果 id 中有 0 的话, 最好是用引号将 id 包裹起来, 比如 "1.10" . 这样的话可以保留 id 中所有的字符 |
author | 指定 changeset 的创建人, 这个是必须的 |
dbms | 指定要执行 changeset 的数据库的类型.When the migration step is running, it checks the database type against this attribute. 你可以作如下的事情: 1. 列举多个数据库类型并用逗号分隔 2. 在数据库类型前加感叹号可以不在指定的数据库中执行 3. 可以使用关键字 all 和 none |
runAlways | 每次运行的时候都执行这个 changeset, 即使之前执行过 |
runOnChange | 在第一次的时候会被执行, 然后每次 changeset 有修改的时候会继续执行 |
Context | 根据运行时的设置控制 changeset 是否执行. 任何字符串都可以作为 context 的名字, 而且是大小写不敏感的 |
Labels | 根据运行时的设置控制 changeset 是否执行. 任何字符串都可以作为 context 的名字, 而且是大小写不敏感的 |
runInTransaction | 指定 changeset 是否作为一个单独的事务执行 (如果可能的话). 默认值为 true |
failOnError | 如果执行时报错的话这个 migration 是否失败, 默认值为 true |
object-quoting-strategy | 这个我用的少, 我就不翻译了 |
runOrder | 控制 changeset 的执行顺序, 用的也少, 按顺序执行就完了 |
created | 存储日期, 版本或者任何字符串的值, 而不是 remarks |
ignore | 忽略这个 changeset 的执行 |
logical-file-path | 当创建 changesets 的唯一标识符时重写文件名和路径. 当需要移动或者重命名 changelog 时会用到这个值 |
可用的子标签
子标签 | 解释 |
---|---|
comment | 指定一个字母-数字格式的标识符, 这个是必须的. 注意, 如果 id 中有 0 的话, 最好是用引号将 id 包裹起来, 比如 "1.10" . 这样的话可以保留 id 中所有的字符 |
preConditions | 指定 changeset 的创建人, 这个是必须的 |
validCheckSum | 给这个 changeset 指定一个有效的 changeset, 而不管数据库里面存储的是什么. 主要使用场景是你要修改已经执行的 changeset 又不想报错时使用.1:any 这个特殊的值将匹配任何的 checksum, 不且 changeset 修改时不会执行 |
rollback | 指定 sql 语句或者 Change Type 如何回滚这个 changeset |
changeset checksums
liquibase 在处理 changeset 的时候, 会先计算校验和并将其存储到 DATABASECHANGELOG 这个表中. 在 changeset 运行之后, 如果 changeset 有任何修改 liquibase 都能通过对比校验和感知到.
如果已经运行的 changeset 发生了修改, 会导致校验和变化,liquibase 会退出执行并且报错: Validation failed: change set check sums <changeset identifer> was: <old checksum> but is now: <newchecksum>
. 这是因为 liquibase 不知道你做了哪些变更. 如果确实是 changeset 需要修改, 而你又想忽略这个错误, 有两个选择:
手动修改 DATABASECHANGELOG 中的记录
第一个方法是手动修改 DATABASECHANGELOG 这个表中对应的记录, 可以将其设置为空值. 这个应该在所有的环境都被部署之后进行. 下次你再运行 liquibase 的时候, 将会更新 checksum 到正确的新值.
<validCheckSum> 属性
第二个方法是给 changeset 增加一个 <validCheckSum>
元素. 这个文本将原来报错的 md5 放到这里来.
runOnChange 属性
校验和通常会和 changeSet 的 runOnChange 属性结合使用. 有时候你并不想增加新的 changeset, 因为只需要知道当前版本, 但是你又想每次更新的时候使用.
runOnChange 默认是 false 的. 如果将其设置为 true 的话, 那么只要 changeset 有更新则会执行.