行继续 Spring SQL ScriptUtils(使用 H2)

Line Continuation Spring SQL ScriptUtils (Using H2)

我有以下 SQL 脚本 (initDB.sql)

CREATE TABLE  FFShareHistorical  (  ID int NOT NULL AUTO_INCREMENT,
                                    PX_LAST  Double DEFAULT NULL, 
                                    PX_OPEN  Double DEFAULT NULL, 
                                    PX_HIGH  Double DEFAULT NULL, 
                                    PX_LOW  Double DEFAULT NULL, 
                                    PRIMARY KEY (ID))

并想使用 Spring 的 ScriptUtils (4.1.4.RELEASE) 来执行它,即

Resource rc = new ClassPathResource("initDB.sql");
ScriptUtils.executeSqlScript(dataSource.getConnection(), rc);

问题是换行符似乎被解释为 SQL 语句的终止,即错误堆栈跟踪看起来像这样

org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 1 of resource class path resource [initDB.sql]: CREATE TABLE FFShareHistorical ( ID int NOT NULL AUTO_INCREMENT, ; nested exception is org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "CREATE TABLE FFSHAREHISTORICAL ( ID INT NOT NULL AUTO_INCREMENT,  "; expected "identifier"; SQL statement:
CREATE TABLE FFShareHistorical ( ID int NOT NULL AUTO_INCREMENT,  [42001-176]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:344)
    at org.h2.message.DbException.getSyntaxError(DbException.java:204)
    at org.h2.command.Parser.readColumnIdentifier(Parser.java:3068)
    at org.h2.command.Parser.parseCreateTable(Parser.java:5722)
    at org.h2.command.Parser.parseCreate(Parser.java:4122)
    at org.h2.command.Parser.parsePrepared(Parser.java:351)
    at org.h2.command.Parser.parse(Parser.java:306)
    at org.h2.command.Parser.parse(Parser.java:278)
    at org.h2.command.Parser.prepareCommand(Parser.java:243)
    at org.h2.engine.Session.prepareLocal(Session.java:442)
    at org.h2.server.TcpServerThread.process(TcpServerThread.java:265)
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:160)
    at java.lang.Thread.run(Unknown Source)

    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:475)
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:393)
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:372)
    at ch.qpmlib.flatfiledatabase.jdbc.dao.FFDBSetup.setupDB(FFDBSetup.java:26)
    at ch.qpmlib.flatfiledatabase.jdbc.main.SpringMain.setupDB(SpringMain.java:30)
    at ch.qpmlib.flatfiledatabase.jdbc.main.SpringMain.main(SpringMain.java:17)
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "CREATE TABLE FFSHAREHISTORICAL ( ID INT NOT NULL AUTO_INCREMENT,  "; expected "identifier"; SQL statement:
CREATE TABLE FFShareHistorical ( ID int NOT NULL AUTO_INCREMENT,  [42001-176]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:344)
    at org.h2.message.DbException.getSyntaxError(DbException.java:204)
    at org.h2.command.Parser.readColumnIdentifier(Parser.java:3068)
    at org.h2.command.Parser.parseCreateTable(Parser.java:5722)
    at org.h2.command.Parser.parseCreate(Parser.java:4122)
    at org.h2.command.Parser.parsePrepared(Parser.java:351)
    at org.h2.command.Parser.parse(Parser.java:306)
    at org.h2.command.Parser.parse(Parser.java:278)
    at org.h2.command.Parser.prepareCommand(Parser.java:243)
    at org.h2.engine.Session.prepareLocal(Session.java:442)
    at org.h2.server.TcpServerThread.process(TcpServerThread.java:265)
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:160)
    at java.lang.Thread.run(Unknown Source)

所以问题是,如何将 ScriptUtils 与多行 SQL 脚本一起使用?特别是我正在寻找某种可以添加到脚本中的 "line continuation" 字符,或者一种告诉 Spring 的 ScriptUtils 删除所有换行符的方法。

您的存档有文档。查看以下位置:

  • spring-framework-4.1.4.RELEASE-dist/spring-framework-4.1.4.RELEASE/docs/javadoc-api/org/springframework/jdbc/datasource/init/
  • spring-framework-4.1.4.RELEASE-dist/spring-framework-4.1.4.RELEASE/docs/spring-framework-reference/

executeSqlScript(...) 方法在内部使用 ResourceDatabasePopulator 用于执行 SQL 脚本。

ResourceDatabasePopulator 提供了一个简单的基于对象的 API,用于使用在外部资源中定义的 SQL 脚本以编程方式填充、初始化或清理数据库。

ResourceDatabasePopulator 提供配置选项 -

  • 字符编码
  • 语句分隔符
  • 评论分隔符
  • 解析和执行脚本时使用的错误处理标志

每个配置选项都有一个默认值

SQL 脚本中的默认语句分隔符设置为 ";"

还有:

  • static void executeSqlScript(Connection connection, EncodedResource resource) 使用语句分隔符、注释定界符和异常处理标志的默认设置执行给定的 SQL 脚本。

  • static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter, String blockCommentEndDelimiter) 执行给定的 SQL 脚本。

  • static void executeSqlScript(Connection connection, Resource resource) 使用语句分隔符、注释定界符和异常处理标志的默认设置执行给定的 SQL 脚本。


但是,当整个脚本中没有 ";" 时,有回退机制到 "\n"。有关详细信息,请参阅@chuchikaeschtli 的回答。

事实证明,使用多行语句是没有问题的。但是,如果语句未以“;”结尾,则 ScriptUtils 将退回到使用“\n”作为分隔符。所以在这种情况下,只需使用“;”终止脚本。即

CREATE TABLE  FFShareHistorical  (  ID int NOT NULL AUTO_INCREMENT,
                                    PX_LAST  Double DEFAULT NULL, 
                                    PX_OPEN  Double DEFAULT NULL, 
                                    PX_HIGH  Double DEFAULT NULL, 
                                    PX_LOW  Double DEFAULT NULL, 
                                    PRIMARY KEY (ID));

会完成任务的。

ScriptUtils 明确支持此类场景。

只需传递 ScriptUtils.EOF_STATEMENT_SEPARATOR 作为 separator 的值。

这是 EOF_STATEMENT_SEPARATOR 的 Javadoc:

End of file (EOF) SQL statement separator: "^^^ END OF SCRIPT ^^^".

This value may be supplied as the separator to executeSqlScript(Connection, EncodedResource, boolean, boolean, String, String, String, String) to denote that an SQL script contains a single statement (potentially spanning multiple lines) with no explicit statement separator. Note that such a script should not actually contain this value; it is merely a virtual statement separator.

此致,

Sam(Spring TestContext Framework 的作者)