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 来准确指定 运行 这些语句的数据库,所以我认为没关系。