我正在使用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工作台中执行此过程,结果成功。
所以,如果有人知道这个问题的原因是什么,请告诉我。
感谢。
答案 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);
}