行继续 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 的作者)
我有以下 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 的作者)