在spring boot schema.sql文件中执行过程的问题

时间:2015-10-02 08:54:58

标签: java mysql sql-server spring stored-procedures

我正在使用schema.sql文件在我的Spring启动应用程序中创建/删除表,它运行正常。

但是当我添加了改变表格的程序时:

DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL;

END IF;
END $$

call Alter_Table;

我收到了com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException异常。

然而,在MySQL工作台中执行此过程,结果成功。

所以,如果有人知道这个问题的原因是什么,请告诉我。

感谢。

3 个答案:

答案 0 :(得分:4)

我发现这个解决方案运行良好,但由于您必须更改SQL脚本,因此它并不理想。

application.properties文件中更改DataSource分隔符属性:

spring.datasource.separator=^;

然后将您的schema.sql文件更新为如下所示:

CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL;

END IF;
END ^;

call Alter_Table ^;

DELIMITER命令仅适用于MySQL CLI客户端和Workbench,不适用于Spring Boot数据库初始化。一旦删除了DELIMITER命令,Spring Boot仍会抛出异常,因为它不会理解存储过程中的;字符不是单独的语句,因此您必须将数据源分隔符属性更改为变通方法。 / p>

答案 1 :(得分:3)

以下是修复:

spring.datasource.separator属性设置为^^^ END OF SCRIPT ^^^,Spring Boot将作为单个语句执行整个schema.sql脚本。

这就是原因:

Spring Boot将schema.sql脚本拆分为语句,然后将每个语句单独发送到数据库以供执行。默认情况下,脚本按分号拆分,因为这是spring.datasource.separator属性(per the documentation)的默认值。这会导致您的schema.sql被拆分,并且执行的第一个语句如下:

DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL

这是无效的SQL,因为美元引用永远不会在语句中终止。

org.springframework.jdbc.datasource.init.ScriptUtils.EOF_STATEMENT_SEPARATOR的javadoc很好地解释了我建议的解决方案的工作原理:

  

文件结束(EOF)SQL语句分隔符:" ^^^脚本结尾^^^"。

     

此值可作为executeSqlScript(Connection,EncodedResource,boolean,boolean,String,String,String,String)的分隔符提供,表示SQL脚本包含单个语句(可能跨越多行),没有明确的语句分隔器。请注意,此类脚本实际上不应包含此值;它只是一个虚拟语句分隔符。

答案 2 :(得分:0)

使用适当的分隔符 EOF_STATEMENT_SEPARATOR 自定义数据库填充器可解决此问题:

@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
    var resource = new ResourceDatabasePopulator(new ClassPathResource("schema.sql"));
    resource.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
    var populator = new CompositeDatabasePopulator();
    populator.addPopulators(resource);
}