Spring JDBC无法在运行SQL脚本时处理DECLARE语句

问题描述 投票:0回答:1

我有一个带有Oracle SQL数据库的Spring CRUD应用程序。

我有几个集成测试,并使用@Sql批注运行.sql文件,该文件在运行测试之前将数据库置于所需的状态。到目前为止,我的任何.sql脚本都没有问题,尽管它们都是非常简单的INSERT和DROP语句。

我现在正在尝试建立一个场景,其中数据库在特定表中保存了数千条记录。我不关心内容,只关心记录数。

为了复制这种情况,我编写了以下SQL脚本:

DECLARE
    id integer := 1;
BEGIN
    WHILE id <= 3000
        LOOP
            INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
            VALUES (id, 'John', 'Smith', 32);
            id := id + 1;
        END LOOP;
END;

我已经使用IntelliJ运行了此脚本,它可以按预期工作。

但是,当我将脚本放入@Sql批注时,遇到以下错误:

org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/setUp.sql]: DECLARE id integer := 1; nested exception is java.sql.SQLException: ORA-06550: line 1, column 23:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

   * & = - + ; < / > at in is mod remainder not rem
   <an exponent (**)> <> or != or ~= >= <= <> and or like like2
   like4 likec between || multiset member submultiset

我对解决方案不知所措;我遇到了类似的问题,其中解决方案只是缺少分号,但是这里似乎不是这样。更令人迷惑的是,我尝试通过@Sql注释运行以下脚本:

BEGIN
    INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
    VALUES (1, 'John', 'Smith', 32);
END;

这产生了以下错误,这更没有意义了:

org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/test.sql]: BEGIN INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE) VALUES (1, 'John', 'Smith', 32); nested exception is java.sql.SQLException: ORA-06550: line 1, column 87:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

   ;

最要注意的是,删除BEGIN和END语句(仅保留INSERT INTO语句)是有效的。

那么Spring JDBC是否不仅仅支持BEGIN / END块?我不知道的预测试@Sql注释是否有限制?还是我错过了明显痛苦的事情?

java spring oracle jdbc plsql
1个回答
1
投票

感谢@MarkRotteveel的建议,我已经找到了解决此问题的方法。

JDBC确实在运行脚本的每一行,就像它是一个单独的语句一样,它与语句块不兼容。这是因为separator默认设置为;符号,导致JDBC将以;结尾的每个代码块都视为一个单独的脚本。我将此分隔符设置为EOF符号,这导致JDBC将整个文件视为一个脚本。

我的原始测试代码看起来像这样:

@Sql(scripts = {"sql/cleanup.sql", "sql/setUp.sql"})
public void testWithThousandsOfRecords() {
  // do tests
}

我的测试代码现在看起来像这样:

@Sql(scripts = "sql/cleanup.sql")
@Sql(scripts = "sql/setUp.sql", config = @SqlConfig(separator = ScriptUtils.EOF_STATEMENT_SEPARATOR))
public void testWithThousandsOfRecords() {
  // do tests
}

请注意,我必须分离清理脚本和设置脚本,因为更改分隔符可能会破坏以前使用的某些脚本。

© www.soinside.com 2019 - 2024. All rights reserved.