带有存储过程的 Spring Boot MySQL 数据库初始化错误

Posted

技术标签:

【中文标题】带有存储过程的 Spring Boot MySQL 数据库初始化错误【英文标题】:Spring Boot MySQL Database Initialization Error with Stored Procedures 【发布时间】:2016-06-21 18:22:13 【问题描述】:

在 Spring Boot 应用程序中,我尝试在运行集成测试之前初始化一些 mysql 数据库表和存储过程,方法是按照documentation 中的建议将 schema.sql 文件放在我的资源目录中。

create table 语句有效,但 create procedure 语句引发异常。导致异常的示例 schema.sql 文件语句如下所示:

DROP PROCEDURE IF EXISTS `database`.FOO;
CREATE PROCEDURE `database`.FOO()

BEGIN
  SELECT * from `database`.employees;
END;

问题是存储过程中的 ; 字符被 Spring ScriptUtils 类解析出来,该类在执行前解析 schema.sql 文件,这会导致 MySQL 在脚本上抛出语法错误.

我查看了ScriptUtils 类,但无法找到一种方法来使用程序转义; 字符。使用\\\ 作为转义字符也不起作用,MySQL 的DELIMITER 命令也是如此。

有没有人能够通过 Spring Boot 使用 schema.sql 文件创建 MySQL 存储过程?如果可以,他们可以举个例子吗?

有关其他信息,以下Spring JIRA issue 解决了相同的主题,但以 Won't Fix 标签结束。

【问题讨论】:

我没有太多信息,但可以试试^ 作为转义字符。 【参考方案1】:

答案很简单。 Spring Boot 有一个 DataSource 分隔符属性,可以在 application.properties 文件中设置:

spring.datasource.separator=^;

然后在 schema.sql 文件中所有不在存储过程中的; 语句都需要使用新的分隔符进行更新。

DROP PROCEDURE IF EXISTS `database`.FOO;
CREATE PROCEDURE `database`.FOO()

BEGIN
  SELECT * from `database`.employees;
END ^;

【讨论】:

不要错过分隔符中的分号 (^;)【参考方案2】:

添加到@Andrews 答案:

使用 Spring Boot 未自动创建的自定义 dataSource 时,可能会发生未使用 spring.datasource.separator 属性的情况。在这种情况下,分隔符不会转发到Populator。这种情况下可以直接在数据源初始化中设置。例如,假设 dataSource 在别处定义,则可以在特殊更新配置文件中使用以下内容:

<jdbc:initialize-database data-source="dataSource" enabled="$initDatabase:false" separator="^;">
    <jdbc:script location="$update.schema.script" />
</jdbc:initialize-database>

或者,当显式声明填充器时:

<bean id="dbPopulator" class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
    <property name="separator" value="^;"/>
    <property name="scripts">
        <list>
            <value>$update.schema.script</value>
        </list>
    </property>
</bean>
<bean id="initDatabase" class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
    <property name="dataSource">
        <ref bean="dataSource"/>
    </property>
    <property name="databasePopulator">
        <ref bean="dbPopulator"/>
    </property>
    <!-- The same can be done for the cleaner: -->
    <!-- <property name="databaseCleaner"><ref bean="dbCleanup"/></property> -->
</bean>

【讨论】:

【参考方案3】:

如果有人像我一样使用 spring-boot + testcontainers 进入这个线程,可以省略分隔符,因为 testcontainers 的解析器是程序 synthax 的aware(尽管仍然不适用于 MS-SQL)。所以原始脚本可以工作:

DROP PROCEDURE IF EXISTS `database`.FOO;
CREATE PROCEDURE `database`.FOO()

BEGIN
  SELECT * from `database`.employees;
END;

【讨论】:

以上是关于带有存储过程的 Spring Boot MySQL 数据库初始化错误的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot - MySQL 到 Postgres 的迁移

Spring boot(带有 jpa 的 mysql):没有名为“entityManagerFactory”的 bean 可用

使用带有 LIKE 的 mysql 本机查询的 spring boot 搜索返回空

Spring Boot集成 MyBatis 操作 MySQL 8

带有访问/刷新令牌的 Spring Boot OAuth2 SSO 未正确存储在数据库中

尝试使用 mysql 学习带有外键和一对多关系关系的 Spring Boot 但是