Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot MySQL Database Initialization Error with Stored Procedures

In a Spring Boot application I am attempting to initialize some MySQL database tables and stored procedures before running integration tests by placing a schema.sql file in my resources directory as recommended in the documentation.

The create table statements work but the create procedure statements throw an exception. A sample schema.sql file statement that causes the exception is shown below:

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

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

The issue is that the ; character within the stored procedure is being parsed out by the Spring ScriptUtils class that parses the schema.sql file before executing it, which then causes MySQL to throw a syntax error on the script.

I have looked at the ScriptUtils class and have not been able to find a way to escape the ; characters with the procedures. Using \\ and \ as escape characters did not work either, as well as the MySQL DELIMITER command.

Has anyone been able to create MySQL stored procedures using the schema.sql file with Spring Boot? If so could they show an example?

For some additional information, the following Spring JIRA issue addresses the same topic but was closed with a Won't Fix label.

like image 456
Andrew Avatar asked Mar 08 '16 00:03

Andrew


People also ask

What is a stored procedure in Spring Boot?

In Relational Database Management Systems (RDBMS), a stored procedure is a batch of prepared SQL code grouped as a logical unit that you store in the database. Stored procedures allow reusability of SQL code. In this post, I will explain how to call MySQL stored procedures from a Spring Boot application. file.

How to initialize a relational database in Spring Boot?

For other Relational databases like MySql, PostgreSql etc.. you need to set spring.datasource.initialization-mode property in Spring Boot configuration file. The default value is embedded. Have to set always to load sql script files, automatically loads schema.sql and data.sql from classpath. You can switch this value to never to not initialize.

Where does Spring Boot load data from?

It loads SQL from the standard root classpath locations: schema.sql and data.sql, respectively. 2.2. For other Relational databases like MySql, PostgreSql etc.. you need to set spring.datasource.initialization-mode property in Spring Boot configuration file. The default value is embedded.

When was the @SQL property introduced in Spring Boot?

This property was introduced in Spring Boot 2.5.0; we need to use spring.datasource.initialization-mode if we are using previous versions of Spring Boot. 6. @Sql Spring also provides the @Sql annotation — a declarative way to initialize and populate our test schema.


2 Answers

The answer turned out to be very simple. Spring Boot has a DataSource separator property that can be set in the application.properties file:

spring.datasource.separator=^;

Then in the schema.sql file all ; statements not within the stored procedure need to be updated with the new separator.

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

BEGIN
  SELECT * from `database`.employees;
END ^;
like image 97
Andrew Avatar answered Oct 10 '22 03:10

Andrew


Adding to @Andrews answer:

When using a custom dataSource that is not automatically created by Spring Boot, it can happen that the spring.datasource.separator property is not used. In this cases the separator is not forwarded to the Populator. In this case it can be set directly in the data source initialization. For example, the following can be used in a special update profile assuming dataSource is defined elsewhere:

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

Or, when the the populator is explicitly stated:

<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>
like image 39
kap Avatar answered Oct 10 '22 04:10

kap