在 Spring Boot 中从文件加载 SQL 触发器

Posted

技术标签:

【中文标题】在 Spring Boot 中从文件加载 SQL 触发器【英文标题】:Load SQL Trigger from file in Spring Boot 【发布时间】:2018-02-21 19:15:58 【问题描述】:

我正在尝试从资源文件夹中的 sql 文件加载自定义数据库触发器。

在我的测试课中,我添加了这个注解@Sql("classpath:custom_script.sql")

在这个文件中,我有 PostgreSQL 数据库的触发器。当我从 PgAdmin 的查询工具执行此脚本时,它们工作正常,但是当我从 Spring Boot 应用程序的测试之前加载它时,出现以下错误:

org.springframework.jdbc.datasource.init.ScriptStatementFailedException:未能执行类路径资源 [custom_script.sql] 的 SQL 脚本语句 #1:创建或替换函数 MY_TRIGGER_PROC() RETURNS TRIGGER AS $CUSTOM_TRG$ DECLARE FOO_V INTEGER;嵌套异常是 org.postgresql.util.PSQLException:未终止的美元报价开始于 SQL CREATE OR REPLACE FUNCTION MY_TRIGGER_PROC() RETURNS TRIGGER AS $CUSTOM_TRG$ DECLARE FOO_V INTEGER 中的位置 64。预计终止 $$

在 custom_script.sql 中,我有三个相关的触发器,如下所示:

CREATE OR REPLACE FUNCTION MY_TRIGGER_PROC()
  RETURNS TRIGGER AS $CUSTOM_TRG$
DECLARE FOO_V INTEGER;
BEGIN
  SELECT COUNT(F.ID)
  INTO FOO_V
  FROM FOO_TABLE F;

  IF FOO_V > 0
  THEN
    RAISE EXCEPTION 'CUSTOM EXCEPTION ERROR MESSAGE FOR ID ', NEW.ID
    USING ERRCODE = 'restrict_violation';
  END IF;
  RETURN NEW;
END;
$CUSTOM_TRG$
LANGUAGE plpgsql;

CREATE TRIGGER CUSTOM_TRG
  BEFORE INSERT
  ON FOO_TABLE
  FOR EACH ROW
EXECUTE PROCEDURE MY_TRIGGER_PROC();

我预计错误是由于分隔符或多行问题,所以我将这些属性添加到属性文件中:

spring.jpa.properties.hibernate.connection.charSet=UTF-8
spring.jpa.properties.hibernate.hbm2ddl.import_files_sql_extractor=org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
spring.datasource.separator=^;

还可以编辑我的脚本,如下面的代码所示,但它没有帮助。你能帮我解决这个问题吗?谢谢。

编辑脚本:

CREATE OR REPLACE FUNCTION MY_TRIGGER_PROC()
  RETURNS TRIGGER AS $CUSTOM_TRG$
DECLARE FOO_V INTEGER;
BEGIN
  SELECT COUNT(F.ID)
  INTO FOO_V
  FROM FOO_TABLE F;

  IF FOO_V > 0
  THEN
    RAISE EXCEPTION 'CUSTOM EXCEPTION ERROR MESSAGE FOR ID ', NEW.ID
    USING ERRCODE = 'restrict_violation';
  END IF;
  RETURN NEW;
END;
$CUSTOM_TRG$
LANGUAGE plpgsql^;

CREATE TRIGGER CUSTOM_TRG
  BEFORE INSERT
  ON FOO_TABLE
  FOR EACH ROW
EXECUTE PROCEDURE MY_TRIGGER_PROC()^;

【问题讨论】:

【参考方案1】:

一种解决方案是在函数定义周围使用单引号,而不是这里使用的 $CUSTOM_TRG$;在类似的情况下,应该再次抛弃 $$ 美元报价,转而使用简单的单引号。但是,整个定义的单引号需要在函数定义中转义引号,如 Postgresql 文档中所述:

使用美元引号(参见第 4.1.2.4 节)来编写函数定义字符串通常很有帮助,而不是普通的单引号语法。如果没有美元引号,函数定义中的任何单引号或反斜杠都必须通过加倍来转义。

因此,在您的示例中,您需要将函数定义中的单引号加倍,发生在 FOO_V > 0 的逻辑中。

【讨论】:

以上是关于在 Spring Boot 中从文件加载 SQL 触发器的主要内容,如果未能解决你的问题,请参考以下文章

在 Eclipse 中从 Spring:boot 项目创建 war 文件

在 Spring Boot 中从命令行设置活动配置文件和配置位置

尝试在 Java Spring Boot 中从 H2 数据库中获取相关实体

未加载 Spring Boot 测试 H2 sql 脚本

如何在apache中从角度调用spring boot api

在 CircleCi 中从 Spring Boot 访问 PostgreSQL 9.6