Spring Boot集成MyBatis调用Oracle存储过程返回Null问题排查
Spring Boot + MyBatis 调用Oracle存储过程返回null问题
问题描述
在Spring Boot项目中使用MyBatis调用Oracle存储过程时遇到问题:存储过程proc_test在SQL Developer中测试正常,但通过应用调用时返回null。
存储过程代码
CREATE OR REPLACE PROCEDURE proc_test ( p_id IN VARCHAR2, p_output OUT VARCHAR2 ) AS BEGIN -- Sample logic: returning a static string for simplicity p_output := 'Sample TEST'; END; /
MyBatis Mapper配置
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.mapping.StatementType; import java.util.Map; @Mapper public interface ProcedureMapper { @Select("{ CALL proc_test(#{id, mode=IN, jdbcType=VARCHAR}, #{output, mode=OUT, jdbcType=VARCHAR}) }") @Options(statementType = StatementType.CALLABLE) void callProcedure(@Param("id") String id, @Param("output") Map<String, Object> output); }
服务层代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class ProcedureService { @Autowired private ProcedureMapper procedureMapper; public String callProcedure(String id) { Map<String, Object> resultMap = new HashMap<>(); procedureMapper.callProcedure(id, resultMap); return (String) resultMap.get("output"); } }
控制器代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ProcedureController { @Autowired private ProcedureService procedureService; @GetMapping("/callProcedure") public String callProcedure(@RequestParam String id) { return procedureService.callProcedure(id); } }
已尝试的操作
- 确认输入参数id已从API正确传递
- 验证存储过程在SQL Developer中运行正常
- 检查MyBatis与Spring Boot配置
- 添加日志确认id已正确传递给存储过程
问题
- 为何存储过程单独运行正常,但Result Map为空且API返回null?
- 是否遗漏了MyBatis或Spring Boot的配置步骤?
- MyBatis处理Oracle存储过程OUT参数是否有已知问题?
问题原因与解决方案
1. 核心问题:OUT参数的Map绑定方式错误
当前Mapper方法中,显式传递Map<String, Object>作为OUT参数载体的写法,无法让MyBatis正确将存储过程的输出值注入到Map中。MyBatis处理CALLABLE语句的OUT参数时,需要调整参数绑定逻辑。
2. 修正方案一:让MyBatis自动返回包含OUT参数的Map
修改Mapper接口方法,无需手动传递Map,改为让MyBatis直接返回存储过程的输出参数映射:
@Mapper public interface ProcedureMapper { @Select("{ CALL proc_test(#{id, mode=IN, jdbcType=VARCHAR}, #{output, mode=OUT, jdbcType=VARCHAR}) }") @Options(statementType = StatementType.CALLABLE) Map<String, Object> callProcedure(@Param("id") String id); }
对应服务层代码修改为:
public String callProcedure(String id) { Map<String, Object> resultMap = procedureMapper.callProcedure(id); return (String) resultMap.get("output"); }
这种方式下,MyBatis会自动将OUT参数output存入返回的Map中。
3. 修正方案二:匹配存储过程参数名
如果坚持手动传递Map,需要确保Mapper中的参数名与存储过程的输出参数名完全一致。存储过程的输出参数是p_output,调整Mapper和服务层代码:
@Mapper public interface ProcedureMapper { @Select("{ CALL proc_test(#{id, mode=IN, jdbcType=VARCHAR}, #{p_output, mode=OUT, jdbcType=VARCHAR}) }") @Options(statementType = StatementType.CALLABLE) void callProcedure(@Param("id") String id, @Param("p_output") Map<String, Object> output); }
服务层获取值时改为:
return (String) resultMap.get("p_output");
4. 其他配置检查
- 确认Oracle JDBC驱动版本与MyBatis、Spring Boot版本兼容,避免版本冲突导致参数绑定失败;
- 开启MyBatis DEBUG日志,查看执行的SQL语句和参数绑定细节,确认OUT参数是否被正确处理;
- 检查MyBatis配置中
mapUnderscoreToCamelCase的设置(如果需要下划线转驼峰,但当前场景参数名无下划线,可忽略)。
5. MyBatis处理Oracle存储过程OUT参数的常见问题
MyBatis对Oracle存储过程的OUT参数支持成熟,常见问题多来自:
- 参数名称不匹配(Mapper中的参数名与存储过程的参数名不一致);
- JDBC类型指定错误(比如将
VARCHAR2错误指定为VARCHAR,部分版本会出现兼容问题); - 语句类型未设置为
StatementType.CALLABLE(你已正确设置,此点可排除); - 参数的
mode属性设置错误(IN/OUT/INOUT混淆)。
内容的提问来源于stack exchange,提问作者Jeffrey Moran
相关产品推荐
相关产品推荐

