使用 liquibase 在 mysql 中创建触发器
Using liquibase to create triggers in mysql
我想使用 liquibase 在 mysql 中创建一个简单的触发器。以下脚本直接从 mysql:
delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END$$
delimiter ;
所以,我想创建一个供 liquibase 使用的变更集,它可以使用更新命令应用此触发器,并且还会在使用 updateSQL 命令时创建一个合适的 sql 脚本。
我已经尝试了变更集中的各种选项,包括 splitStatements 和 endDelimiter,但只能获得适用于 update 命令或 updateSQL 命令的内容。两者都不行。
这是一个使用格式化 sql 的示例更改集,当我使用更新命令时它工作正常,但当我使用 updateSQL 命令
时不会创建合适的 sql
-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END
-- rollback DROP TRIGGER IF EXISTS myTrigger;
这里是我想要的 updateSQL,但更新失败:
-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false
delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END$$
delimiter ;
-- rollback DROP TRIGGER IF EXISTS myTrigger;
基本问题是
- mysql 脚本需要分隔符 $$ 和分隔符 ;在里面
- 如果 liquibase 的 jdbc 调用以分隔符 $$ 开头,则调用将失败
您的触发器可以很容易地转换为单语句形式:
CREATE TRIGGER myTrigger
BEFORE INSERT
ON myTable
FOR EACH ROW
SET NEW.my_timestamp = COALESCE(NEW.my_timestamp, NOW());
不需要重新分配分隔符。
如果 NULL 插入到该列中,因为该列根本没有列在 INSERT 查询的列列表中,那么您可以简单地在列定义中使用 DEFAULT CURRENT_TIMESTAMP
,并且不需要触发器。但如果明确设置了 NULL 值,则此方法不适用。
我同意@Akina 的观点,一个好的解决方案是不使用触发器,或者将它们压缩成单个语句。
我正在尝试将 liquibase 引入现有数据库,因此希望能够在最初保持不变。然后应用更改以使其更简单。
所以,基本问题是
- mysql 脚本需要分隔符 $$ 和分隔符 ;其中
- 如果 liquibase 的 jdbc 调用以分隔符 $$ 开头,则调用将失败
经过多次尝试,我想出的解决方案依赖于使用 gradle 插件到 运行 liquibase updateSql 命令。我无法单独使用 liquibase 来实现它。我基本上注释了 liquibase 无法识别的代码部分,然后 post 处理 liquibase 创建的脚本文件以取消对语句的注释。
这是我的变更集,格式为 sql:
-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false stripComments:false
-- delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END-- $$
-- delimiter ;
-- rollback DROP TRIGGER IF EXISTS myTrigger;
我可以 运行 liquibase 更新它并且它被正确应用。
我配置 gradle 使用 liquibase 插件,还使用 outputFile : "$projectDir/update.sql"
然后更新了 build.gradle 文件以扩展插件添加的 updateSql 任务,以更改输出中我想要的语句的注释
updateSQL{
doLast {
ant.replace(file: "$projectDir/update.sql", token: '-- delimiter', value: 'delimiter')
ant.replace(file: "$projectDir/update.sql", token: '-- $$', value: '$$')
}
}
不需要玩delimiter,只需添加changeSet属性splitStatements = "false",即yaml版本是:
- changeSet:
changes:
- sql:
dbms: 'mysql'
splitStatements: false
sql: |
CREATE TRIGGER myTrigger BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END;
我想使用 liquibase 在 mysql 中创建一个简单的触发器。以下脚本直接从 mysql:
delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END$$
delimiter ;
所以,我想创建一个供 liquibase 使用的变更集,它可以使用更新命令应用此触发器,并且还会在使用 updateSQL 命令时创建一个合适的 sql 脚本。
我已经尝试了变更集中的各种选项,包括 splitStatements 和 endDelimiter,但只能获得适用于 update 命令或 updateSQL 命令的内容。两者都不行。
这是一个使用格式化 sql 的示例更改集,当我使用更新命令时它工作正常,但当我使用 updateSQL 命令
时不会创建合适的 sql-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END
-- rollback DROP TRIGGER IF EXISTS myTrigger;
这里是我想要的 updateSQL,但更新失败:
-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false
delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END$$
delimiter ;
-- rollback DROP TRIGGER IF EXISTS myTrigger;
基本问题是
- mysql 脚本需要分隔符 $$ 和分隔符 ;在里面
- 如果 liquibase 的 jdbc 调用以分隔符 $$ 开头,则调用将失败
您的触发器可以很容易地转换为单语句形式:
CREATE TRIGGER myTrigger
BEFORE INSERT
ON myTable
FOR EACH ROW
SET NEW.my_timestamp = COALESCE(NEW.my_timestamp, NOW());
不需要重新分配分隔符。
如果 NULL 插入到该列中,因为该列根本没有列在 INSERT 查询的列列表中,那么您可以简单地在列定义中使用 DEFAULT CURRENT_TIMESTAMP
,并且不需要触发器。但如果明确设置了 NULL 值,则此方法不适用。
我同意@Akina 的观点,一个好的解决方案是不使用触发器,或者将它们压缩成单个语句。
我正在尝试将 liquibase 引入现有数据库,因此希望能够在最初保持不变。然后应用更改以使其更简单。
所以,基本问题是
- mysql 脚本需要分隔符 $$ 和分隔符 ;其中
- 如果 liquibase 的 jdbc 调用以分隔符 $$ 开头,则调用将失败
经过多次尝试,我想出的解决方案依赖于使用 gradle 插件到 运行 liquibase updateSql 命令。我无法单独使用 liquibase 来实现它。我基本上注释了 liquibase 无法识别的代码部分,然后 post 处理 liquibase 创建的脚本文件以取消对语句的注释。
这是我的变更集,格式为 sql:
-- liquibase formatted sql
-- changeset pcoates33:trigger-1 splitStatements:false stripComments:false
-- delimiter $$
CREATE TRIGGER myTrigger
BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END-- $$
-- delimiter ;
-- rollback DROP TRIGGER IF EXISTS myTrigger;
我可以 运行 liquibase 更新它并且它被正确应用。
我配置 gradle 使用 liquibase 插件,还使用 outputFile : "$projectDir/update.sql"
然后更新了 build.gradle 文件以扩展插件添加的 updateSql 任务,以更改输出中我想要的语句的注释
updateSQL{
doLast {
ant.replace(file: "$projectDir/update.sql", token: '-- delimiter', value: 'delimiter')
ant.replace(file: "$projectDir/update.sql", token: '-- $$', value: '$$')
}
}
不需要玩delimiter,只需添加changeSet属性splitStatements = "false",即yaml版本是:
- changeSet:
changes:
- sql:
dbms: 'mysql'
splitStatements: false
sql: |
CREATE TRIGGER myTrigger BEFORE INSERT ON myTable FOR EACH ROW
BEGIN
IF(NEW.my_timestamp IS NULL) THEN
SET NEW.my_timestamp = now();
END IF;
END;