重新定义在包含文件中仍然可见的本地 liquibase 属性
redefine local liquibase properies that are still visible in included files
我的一些 table 实现了需要特定列的概念。我想避免将这些列的变更集复制到所有相关的 table,而是重用一个模板来创建实际的变更集。
根据我在网上找到的不同想法,我尝试了这个:
db/templates/0004-create-validity-period-data-template.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.5.xsd">
<include file="../templates/0002-create-versioned-data-template.xml" relativeToChangelogFile="true" />
<changeSet author="${table.author}" id="Create ValidityPeriodData for ${table.name}" >
<comment>Create columns of super class ValidityPeriodData for table ${table.name}</comment>
<addColumn tableName="${table.name}" >
<column name="valid_from" type="date" remarks="the earliest point in time when this entry is valid" />
<column name="valid_until" type="date" remarks="the last point in time when this entry is valid" />
</addColumn>
</changeSet>
</databaseChangeLog>
db/changelog/0017-create-credential-table.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.5.xsd">
<property name="table.name" value="login" />
<property name="table.author" value="guess ;-)" />
<include file="../templates/0004-create-validity-period-data-template.xml" relativeToChangelogFile="true" />
<changeSet author="${table.author}" id="Create Credential table">
<addColumn tableName="${table.name}">
<column name="login_id" type="${uuid_type}"/>
<column name="password" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="salt" type="VARCHAR(128)"/>
</addColumn>
<addForeignKeyConstraint baseColumnNames="login_id"
baseTableName="${table.name}"
constraintName="fk_credential_of_login"
onDelete="RESTRICT"
onUpdate="RESTRICT"
referencedColumnNames="id"
referencedTableName="login"/>
</changeSet>
</databaseChangeLog>
问题
属性(table.name、table.author)默认为global="true"
,这意味着它们在所有变更集文件中都可见,但不能overwritten/redefined。所以这只适用于单个 table,这违背了目的。
如果我将它们声明为 global="false"
,我可以为每个需要这些列的 table 重新定义它们,但是现在包含的文件看不到这些属性。
问题
有没有办法重新定义或覆盖不同变更集文件的属性(就像 global="false"
所做的那样),但仍然让它们在包含的文件中以递归方式表现得像 global="true"
。
我认为您对 liquibase changeSets 的用法有误解。
ChangeSet 应该是原子的并遵循 "one action - one changeSet" 概念。它不应该是某种 "reusable function"。这种方法可能会损坏您的数据库模式。因此,您不会删除旧的 changeSets
所以我建议您为每个 table 需要添加列的地方编写变更集。
另外,看看这篇文章:Trimming ChangeLog Files
背景
我看过liquibase的源代码。事实证明当前的实现(在版本 3.6.2、3.6.3、3.8.0 中)有点奇怪。
private ChangeLogParameter findParameter(String key, DatabaseChangeLog changeLog) {
ChangeLogParameter result = null;
List<ChangeLogParameter> found = new ArrayList<>();
for (ChangeLogParameter param : changeLogParameters) {
if (param.getKey().equalsIgnoreCase(key) && param.isValid()) {
found.add(param);
}
}
if (found.size() == 1) {
// this case is typically a global param, but could also be a unique non-global param in one specific
// changelog
result = found.get(0);
} else if (found.size() > 1) {
for (ChangeLogParameter changeLogParameter : found) {
if (changeLogParameter.getChangeLog().equals(changeLog)) {
result = changeLogParameter;
}
}
}
return result;
}
您还需要知道表达式会在解析 changeSet 后立即展开。 changeSets 中定义的参数尚未读取,不能考虑。
所以第一次遇到一个参数时,它实际上被视为global=true
,不管是否是这种情况。
不会记录第二个同名的全局参数。但是,将记录第二个本地参数。
一旦参数列表包含第二个具有相同名称的 ChangeLogParameter,它们将以不同方式展开。现在它会查找在同一个变更集文件中定义的该参数的最后定义版本 - 但无论是全局还是本地都没有关系。
回答
所以回答我自己的问题。 liquibase 的当前实现不支持那种东西。最重要的是,它在扩展表达式方面表现得有些不一致。
解决方案?
我在 GitHub 上用 liquibase CORE-3493 and provided a possible solution 提交了错误报告。
编辑:
此更改已包含在版本 3.10.2 中。但是请注意,我在不知不觉中引入了一项重大更改 issue #1293。这对新项目无关紧要,但如果已经使用了变量,则可能会破坏现有项目。问题中建议了解决方法。
我的一些 table 实现了需要特定列的概念。我想避免将这些列的变更集复制到所有相关的 table,而是重用一个模板来创建实际的变更集。
根据我在网上找到的不同想法,我尝试了这个:
db/templates/0004-create-validity-period-data-template.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.5.xsd">
<include file="../templates/0002-create-versioned-data-template.xml" relativeToChangelogFile="true" />
<changeSet author="${table.author}" id="Create ValidityPeriodData for ${table.name}" >
<comment>Create columns of super class ValidityPeriodData for table ${table.name}</comment>
<addColumn tableName="${table.name}" >
<column name="valid_from" type="date" remarks="the earliest point in time when this entry is valid" />
<column name="valid_until" type="date" remarks="the last point in time when this entry is valid" />
</addColumn>
</changeSet>
</databaseChangeLog>
db/changelog/0017-create-credential-table.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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.5.xsd">
<property name="table.name" value="login" />
<property name="table.author" value="guess ;-)" />
<include file="../templates/0004-create-validity-period-data-template.xml" relativeToChangelogFile="true" />
<changeSet author="${table.author}" id="Create Credential table">
<addColumn tableName="${table.name}">
<column name="login_id" type="${uuid_type}"/>
<column name="password" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="salt" type="VARCHAR(128)"/>
</addColumn>
<addForeignKeyConstraint baseColumnNames="login_id"
baseTableName="${table.name}"
constraintName="fk_credential_of_login"
onDelete="RESTRICT"
onUpdate="RESTRICT"
referencedColumnNames="id"
referencedTableName="login"/>
</changeSet>
</databaseChangeLog>
问题
属性(table.name、table.author)默认为global="true"
,这意味着它们在所有变更集文件中都可见,但不能overwritten/redefined。所以这只适用于单个 table,这违背了目的。
如果我将它们声明为 global="false"
,我可以为每个需要这些列的 table 重新定义它们,但是现在包含的文件看不到这些属性。
问题
有没有办法重新定义或覆盖不同变更集文件的属性(就像 global="false"
所做的那样),但仍然让它们在包含的文件中以递归方式表现得像 global="true"
。
我认为您对 liquibase changeSets 的用法有误解。
ChangeSet 应该是原子的并遵循 "one action - one changeSet" 概念。它不应该是某种 "reusable function"。这种方法可能会损坏您的数据库模式。因此,您不会删除旧的 changeSets
所以我建议您为每个 table 需要添加列的地方编写变更集。
另外,看看这篇文章:Trimming ChangeLog Files
背景
我看过liquibase的源代码。事实证明当前的实现(在版本 3.6.2、3.6.3、3.8.0 中)有点奇怪。
private ChangeLogParameter findParameter(String key, DatabaseChangeLog changeLog) {
ChangeLogParameter result = null;
List<ChangeLogParameter> found = new ArrayList<>();
for (ChangeLogParameter param : changeLogParameters) {
if (param.getKey().equalsIgnoreCase(key) && param.isValid()) {
found.add(param);
}
}
if (found.size() == 1) {
// this case is typically a global param, but could also be a unique non-global param in one specific
// changelog
result = found.get(0);
} else if (found.size() > 1) {
for (ChangeLogParameter changeLogParameter : found) {
if (changeLogParameter.getChangeLog().equals(changeLog)) {
result = changeLogParameter;
}
}
}
return result;
}
您还需要知道表达式会在解析 changeSet 后立即展开。 changeSets 中定义的参数尚未读取,不能考虑。
所以第一次遇到一个参数时,它实际上被视为global=true
,不管是否是这种情况。
不会记录第二个同名的全局参数。但是,将记录第二个本地参数。
一旦参数列表包含第二个具有相同名称的 ChangeLogParameter,它们将以不同方式展开。现在它会查找在同一个变更集文件中定义的该参数的最后定义版本 - 但无论是全局还是本地都没有关系。
回答
所以回答我自己的问题。 liquibase 的当前实现不支持那种东西。最重要的是,它在扩展表达式方面表现得有些不一致。
解决方案?
我在 GitHub 上用 liquibase CORE-3493 and provided a possible solution 提交了错误报告。
编辑: 此更改已包含在版本 3.10.2 中。但是请注意,我在不知不觉中引入了一项重大更改 issue #1293。这对新项目无关紧要,但如果已经使用了变量,则可能会破坏现有项目。问题中建议了解决方法。