【问题标题】:Spring Boot schema.sql, initializing database using PL/SQLSpring Boot schema.sql,使用 PL/SQL 初始化数据库
【发布时间】:2026-02-06 19:35:02
【问题描述】:

我正在做一个项目,我必须使用 Oracle Database 12c,并且我必须手动编写所有查询(所以我不能使用 Spring Data)。 对于创建所有表和关系,我使用 schema.sql,对于模板数据,我使用 data.sql。

我在检查表或数据是否已经存在时遇到了问题。 在 MySQL 中创建表就像“如果不存在则创建表”。 不幸的是,在 PL/SQL 中,没有“如果不存在”的等价物。我将此功能替换为:

begin
execute immediate
'CREATE TABLE user_data (
  some data
)';
exception when others then if SQLCODE = -955 then null; else raise; end if;
end;

当我在 SQL Developer 或 Intellij 的 SQL 控制台中运行此脚本时它可以工作,但是当我想运行应用程序并且 Spring Boot 尝试从 schema.sql 执行脚本时会出现问题。

终端的输出告诉我们:

nested exception is java.sql.SQLException: ORA-06550: line 8, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

* & = - + ; < / > at in is mod remainder not rem return
returning <an exponent (**)> <> or != or ~= >= <= <> and or
like like2 like4 likec between into using || multiset bulk
member submultiset

所以看起来 Spring Boot 不知道它应该在“开始”和“结束”之间运行语句。 知道如何管理数据库初始化问题吗?

作为一种解决方法,我可以在每次运行应用程序时删除表,但这不是最佳解决方案(当有人第一次运行应用程序时它不会工作)。

【问题讨论】:

  • 查看 Liquidbase 或 Flyway。有专门用于此的库
  • 'CREATE TABLE user_data ( some data 它应该有一些列而不是一些数据
  • @pvpkiran,很遗憾,我不能使用 Liquidbase 或 Flyway 之类的库...
  • @XING 这只是一个例子。在我的应用程序中,我有一些列,但没有必要在此处显示它们,因为问题与它们无关

标签: java oracle spring-boot plsql oracle12c


【解决方案1】:

首先,我想分享两个似乎与这个问题相关的主题:

在那里你会找到一个可行的解决方案:创建一个存储过程并在你的schema.sql语句中使用

call recreate_table('USER_DATA','CREATE TABLE USER_DATA (SOME DATA)');  

CALL 语句在不同的数据库中广泛使用,缩短为只有一个分号的语句,因此效果很好。

其次,我可能只是假设,主要问题是 PL/SQL 中的匿名块(以及其他可能包含多个分号的足够复杂的语句)应该由/ 字符。我建议您尝试将此字符附加到脚本的末尾,查看thisthis 的答案,如果不起作用,请创建一个存储过程。

还请注意,还有另一种方法可以检查表的存在(通过此 等待异常 模式):

select count(*)
  from user_tables t
 where t.table_name = 'USER_DATA'
   and rownum < 2

【讨论】:

  • 谢谢,创建程序帮助了我。但是我必须在 SQL Developer 中创建一个过程,因为当我在 schema.sql 中运行“创建或替换过程”时存在完全相同的问题。 Spring 不知道应该在“创建或替换”和“/”之间运行脚本。它在第一个分号后刹车。因此,在运行应用程序之前,我必须在每个环境中的数据库中创建一个过程,我想我必须创建其他过程来创建表之间的关系。不过,感谢您的帮助。我想将您的回答标记为有用,但我没有声誉积分。
  • 你试过玩spring.datasource.separator参数吗?看来,它在某些情况下有效:*.com/a/45097894/9145106*.com/a/35871495/9145106
  • 是的,我尝试过使用不同的分隔符,但出现了一些错误。我将使用存储过程。