Liquibase:<changeSet> 在 <sql> 中有多个 SQL 语句使用参数
Liquibase: <changeSet> with multiple SQL statements in <sql> using parameters
我需要 运行 Liquibase 中的准备语句:
<changeSet id="53" author="foo">
<sql dbms="!h2, mysql" splitStatements="true">
SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
SET @constraint_name = (
SELECT rc.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu
ON kcu.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG
AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
WHERE kcu.TABLE_NAME = @table_name
AND kcu.COLUMN_NAME = @column_name
);
SET @s = concat('ALTER TABLE ', @table_name, ' DROP FOREIGN KEY ', @constraint_name);
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt
</sql>
</changeSet>
如果我将 splitStatements
设置为 true,那么我认为参数不会跨语句持续存在,因此可以理解我收到一条错误消息,指出 @s
为 NULL:
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'NULL' at line 1 [Failed SQL: PREPARE stmt FROM @s]
如果我将 splitStatements
设置为 false,并且还删除除前两个 SET
之外的所有内容以确保它不是导致问题的嵌套 SELECT
,我得到以下信息:
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'SET @column_name = 'ACTOR_ID'' at line 2 [Failed SQL: SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';]
然后我假设 endDelimiter
默认为 ;
的问题。所以我尝试了 FOO
:
<sql dbms="!h2, mysql" splitStatements="false" endDelimiter="FOO">
SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
FOO
</sql>
我得到...
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'SET @column_name = 'ACTOR_ID';
FOO' at line 2 [Failed SQL: SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
FOO]
我觉得我不明白这是怎么回事。我检查了 SQL 在 MySQL Workbench 中是否有效。有什么见解吗?
更新
所以,我认为 splitStatements=false 让我克服了 NULL @s
错误,因此假设参数(或“user/session 变量”为我现在知道如何称呼他们)分裂时一定不能坚持。但那都是错误的。这些变量确实跨语句持续存在:在会话期间。
splitStatements=false 只是用一个新错误掩盖了原始错误,这确实与 MySQL 不允许同时进行多个查询有关。当我使用 allowMultiQueries=true 解锁 that 时,我得到一个指向第 1 行的 new 错误,它最终让我修复了 original 错误,这是我的 table 名称错误(大写而不是小写)。
我从未意识到的是,table 名称错误也导致 @s
以 NULL 结尾。
旧的“解决方案”
我没有意识到 MySQL 默认情况下不允许多个查询。我不得不在 JDBC URL 中添加它作为查询参数:
jdbc:mysql://%s:%d/%s?user=root&allowMultiQueries=true
据我了解,这不是 portable 路径。但是由于我使用 Liquibase 来准确指定 运行 这些语句的数据库,所以我认为没关系。
我需要 运行 Liquibase 中的准备语句:
<changeSet id="53" author="foo">
<sql dbms="!h2, mysql" splitStatements="true">
SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
SET @constraint_name = (
SELECT rc.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu
ON kcu.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG
AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
WHERE kcu.TABLE_NAME = @table_name
AND kcu.COLUMN_NAME = @column_name
);
SET @s = concat('ALTER TABLE ', @table_name, ' DROP FOREIGN KEY ', @constraint_name);
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt
</sql>
</changeSet>
如果我将 splitStatements
设置为 true,那么我认为参数不会跨语句持续存在,因此可以理解我收到一条错误消息,指出 @s
为 NULL:
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'NULL' at line 1 [Failed SQL: PREPARE stmt FROM @s]
如果我将 splitStatements
设置为 false,并且还删除除前两个 SET
之外的所有内容以确保它不是导致问题的嵌套 SELECT
,我得到以下信息:
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'SET @column_name = 'ACTOR_ID'' at line 2 [Failed SQL: SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';]
然后我假设 endDelimiter
默认为 ;
的问题。所以我尝试了 FOO
:
<sql dbms="!h2, mysql" splitStatements="false" endDelimiter="FOO">
SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
FOO
</sql>
我得到...
Reason: liquibase.exception.DatabaseException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near 'SET @column_name = 'ACTOR_ID';
FOO' at line 2 [Failed SQL: SET @table_name = 'AUDIT_EVENT';
SET @column_name = 'ACTOR_ID';
FOO]
我觉得我不明白这是怎么回事。我检查了 SQL 在 MySQL Workbench 中是否有效。有什么见解吗?
更新
所以,我认为 splitStatements=false 让我克服了 NULL @s
错误,因此假设参数(或“user/session 变量”为我现在知道如何称呼他们)分裂时一定不能坚持。但那都是错误的。这些变量确实跨语句持续存在:在会话期间。
splitStatements=false 只是用一个新错误掩盖了原始错误,这确实与 MySQL 不允许同时进行多个查询有关。当我使用 allowMultiQueries=true 解锁 that 时,我得到一个指向第 1 行的 new 错误,它最终让我修复了 original 错误,这是我的 table 名称错误(大写而不是小写)。
我从未意识到的是,table 名称错误也导致 @s
以 NULL 结尾。
旧的“解决方案”
我没有意识到 MySQL 默认情况下不允许多个查询。我不得不在 JDBC URL 中添加它作为查询参数:
jdbc:mysql://%s:%d/%s?user=root&allowMultiQueries=true
据我了解,这不是 portable 路径。但是由于我使用 Liquibase 来准确指定 运行 这些语句的数据库,所以我认为没关系。