Spring Data调用Oracle存储过程触发PLS-00306错误,求排查原因
解决Spring Data调用Oracle存储过程时的PLS-00306错误
我碰到过好几个类似的场景,这个错误本质就是调用存储过程/函数时的参数和定义不匹配,结合你用的Spring Boot 1.5.9、Hibernate 5.2.12和Oracle 12c环境,大概率是下面这些原因之一:
1. 参数数量完全对不上
首先最直观的:你Oracle端的LOGIN存储过程/函数定义的参数个数,和Spring Data Repository方法里传的参数数量不一致。比如存储过程要求3个参数(2个输入+1个输出),但你的Repository方法只传了2个输入参数,漏了输出参数的声明;或者反过来多传了参数。
尤其要注意Oracle的IN/OUT/IN OUT模式参数,哪怕是输出参数,也需要在Repository方法里明确声明,不能省略。
2. 参数类型不匹配
这个是最常见的坑,比如:
- Oracle端参数是
VARCHAR2(50),但你Java里传了Integer类型; - Oracle端是
DATE类型,Java里用了LocalDateTime但Hibernate 5.2在这个版本下对新日期类型的映射支持有小坑,没正确转换; - Oracle端是
NUMBER(18,0),Java里用了Short,超出类型范围也会触发这个错误; - 如果存储过程用了PL/SQL自定义类型(比如RECORD、TABLE),Spring Data默认不支持,得额外配置类型转换器,这也会导致类型不匹配。
3. 参数顺序或名称绑定错误
Oracle存储过程调用时,参数匹配分按位置绑定和按名称绑定两种:
- 如果你没在Repository方法里用
@Param指定参数名,Spring Data会默认按位置匹配,这时候如果参数顺序和存储过程定义的顺序不一致,就会报错; - 如果你用了
@Param,要确保注解里的参数名和Oracle存储过程的参数名完全一致(比如存储过程参数叫p_username,你@Param写的username,就会匹配失败)。
4. 存储过程的Schema或名称拼写错误
比如你的LOGIN存储过程是在SCOTT用户下,而Spring Data连接Oracle用的是其他用户,没加Schema前缀(比如SCOTT.LOGIN),导致Oracle找不到正确的存储过程;或者你把存储过程名拼错了(比如写成LOGINN),刚好数据库里有个同名但参数不同的过程,就会触发PLS-00306错误。
5. 输出/输入输出参数的处理错误
如果你的LOGIN是带输出参数的存储过程,或者是返回值的函数,Spring Data的声明方式不对也会报错:
- 存储过程的输出参数:需要在
@Param里指定mode = ParameterMode.OUT,比如:@Procedure(name = "LOGIN") void login(@Param("p_username") String username, @Param("p_password") String password, @Param(value = "p_result", mode = ParameterMode.OUT) Integer result); - 如果是Oracle函数:要在
@Procedure里加上function = true,并且Repository方法的返回类型要和函数的返回类型匹配,比如:@Procedure(name = "LOGIN", function = true) String login(@Param("p_username") String username, @Param("p_password") String password);
排查建议
- 先去Oracle端确认
LOGIN的准确定义:用DESC LOGIN或者查看PL/SQL源码,把参数的名称、类型、模式都记下来; - 对比Repository方法的参数,逐一核对数量、类型、顺序、注解配置;
- 先用纯JDBC代码调用一次存储过程,如果JDBC能成功,那问题肯定出在Spring Data的配置上;
- 检查Hibernate的类型映射配置,比如是否在
application.properties里设置了正确的Oracle方言:spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
内容的提问来源于stack exchange,提问作者Rasshu
相关产品推荐
相关产品推荐

