如何使用 liquibase 和 mysql 修复 SQL 语法错误来创建触发器

How to fix SQL syntax error using liquibase and mysql to create trigger

我正在为 MySQL 数据库设置第一个 liquibase maven 项目。在创建触发器之前一切顺利。

我认为这是 liquibase 的问题,JDBC 没有正确处理多重语句 SQL,但我不知道我遗漏了什么。

这是我的 pom 依赖关系

    <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-parent</artifactId>
      <version>3.5.3</version>
      <type>pom</type>
    </dependency>

    <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-core</artifactId>
      <version>3.5.3</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>

    <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-maven-plugin</artifactId>
      <version>3.6.3</version>
    </dependency>

这是我的 liquibase 包含文件

<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.0.xsd">

  <changeSet id="event_horizon_1_0_0" author="lmtyler" dbms="mysql">
    <sql>
      drop trigger if exists ai_event_approval;
    </sql>
  </changeSet>

  <changeSet id="event_horizon_1_0_1" author="lmtyler" dbms="mysql">
    <sqlFile splitStatements="false" stripComments="false" endDelimiter="DONE" path="01__ai_event_approval.sql" relativeToChangelogFile="true" />
  </changeSet>

</databaseChangeLog>

这是我的 sql 文件

CREATE DEFINER ='evclient'@'%' TRIGGER ai_event_approval
    AFTER INSERT
    ON event_approval
    FOR EACH row
begin
    insert into event_approval_log (rowAction,
                                    actionTs,
                                    event,
                                    requestorEmail,
                                    requestReason,
                                    statusType,
                                    approverUserId,
                                    approverReason,
                                    lastChangTs)
        values ('I',
                current_timestamp(6),
                new.event,
                new.requestorEmail,
                new.requestReason,
                new.statusType,
                new.approverUserId,
                new.approverReason,
                new.lastChangTs);
end;
# DONE

我希望通过设置 splitStatements、stripComments 和 endDelimiter,我可以让 liquibase 将整个 SQL 作为一个发送到 JDBC。

但是我收到这个错误

[ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:3.6.3:update (default) on project event-horizon-mysql: Error setting up or running Liquibase: Migration failed for change set /Users/lmtyler/OneDrive - Walmart Inc/workspace/code/event-horizon/event-horizon-mysql/src/main/java/resources/liquibase/schema/triggers/02__au_event_approval.sql::event_horizon_1_0_1::lmtyler:
[ERROR]      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 '' at line 23 [Failed SQL: CREATE TRIGGER au_event_approval
[ERROR]     AFTER UPDATE
[ERROR]     ON event_approval
[ERROR]     FOR EACH row
[ERROR] begin
[ERROR]     insert into event_approval_log (rowAction,
[ERROR]                                     actionTs,
[ERROR]                                     event,
[ERROR]                                     requestorEmail,
[ERROR]                                     requestReason,
[ERROR]                                     statusType,
[ERROR]                                     approverUserId,
[ERROR]                                     approverReason,
[ERROR]                                     lastChangTs)
[ERROR]     values ('U',
[ERROR]             current_timestamp(6),
[ERROR]             new.event,
[ERROR]             new.requestorEmail,
[ERROR]             new.requestReason,
[ERROR]             new.statusType,
[ERROR]             new.approverUserId,
[ERROR]             new.approverReason,
[ERROR]             new.lastChangTs)]

随着@Jens 的建议睡了一晚上我终于明白了这个问题。

首先,如果您看到我的 post,错误不是我认为的 SQL。 我以为是 AFTER INSERT 引发了错误,但实际上是 AFTER UPDATE

关键是要确保设置splitStatements:false,不需要设置endDelimiter

这里有两个有效的例子:

<changeSet id="event_horizon_1_0_1" author="lmtyler" dbms="mysql">
    <sqlFile splitStatements="false" stripComments="false" path="01__ai_event_approval.sql" relativeToChangelogFile="true"/>
</changeSet>

用这个 sql 文件

CREATE DEFINER ='evclient'@'%' TRIGGER ai_event_approval
    AFTER INSERT
    ON event_approval
    FOR EACH row
begin
    insert into event_approval_log (rowAction,
                                    actionTs,
                                    event,
                                    requestorEmail,
                                    requestReason,
                                    statusType,
                                    approverUserId,
                                    approverReason,
                                    lastChangTs)
        values ('I',
                current_timestamp(6),
                new.event,
                new.requestorEmail,
                new.requestReason,
                new.statusType,
                new.approverUserId,
                new.approverReason,
                new.lastChangTs);
end;

这里使用的是 SQL 格式

--changeset lmtyler:event_horizon_1_0_1 dbms:mysql splitStatements:false
CREATE TRIGGER au_event_approval
    AFTER UPDATE
    ON event_approval
    FOR EACH row
begin
    insert into event_approval_log (rowAction,
                                    actionTs,
                                    event,
                                    requestorEmail,
                                    requestReason,
                                    statusType,
                                    approverUserId,
                                    approverReason,
                                    lastChangTs)
    values ('U',
            current_timestamp(6),
            new.event,
            new.requestorEmail,
            new.requestReason,
            new.statusType,
            new.approverUserId,
            new.approverReason,
            new.lastChangTs);
end;

我在 sql 标签内执行触发器时遇到了同样的问题。如果您在 liquibase 中执行一段代码,请不要忘记将 splitStatements:false 添加到您的 sql 标签中。

<changeSet id="your_id" author="your_name">

    <comment>your comments</comment>

    <sql splitStatements="false">
        CREATE TRIGGER trigger_name
        BEFORE UPDATE ON table_name FOR EACH ROW
        BEGIN
        --Your Code Block
        END;
    </sql>
</changeSet>