Spring Boot+MyBatis调用MySQL存储过程报错:参数3不是OUT参数
解决MyBatis调用MySQL存储过程时「Parameter number 3 is not an OUT parameter」错误
我之前也踩过这个坑,咱们来一步步捋清楚问题出在哪,再给出靠谱的修复方案。
问题根源
你当前的写法里,MyBatis没办法正确识别存储过程的OUT参数——你的Mapper接口直接返回Result对象,但MyBatis需要一个明确的载体来绑定OUT参数的值。现在XML映射里写的#{out0,mode=OUT,jdbcType=INTEGER},这个out0没有对应的入参对象属性,MyBatis会默认把它当成IN参数处理,这就和存储过程定义的OUT参数冲突,直接抛出了那个错误。
另外还有个小问题:你的测试代码里直接new testDao()是错误的!MyBatis的Mapper接口是动态生成代理类的,必须通过Spring容器或者SqlSession获取实例,不能直接实例化接口。
修复方案
方案1:用Map作为参数与结果载体(最简单直接)
这种方式不需要修改实体类,用Map传递IN参数并接收OUT参数:
- 修改Mapper接口:
public interface TestDao { void testSP(Map<String, Object> params); }
- 修改XML映射文件:
<select id="testSP" statementType="CALLABLE"> {call testSP( #{id, mode=IN, jdbcType=VARCHAR}, #{name, mode=IN, jdbcType=VARCHAR}, #{out0, mode=OUT, jdbcType=INTEGER}, #{out1, mode=OUT, jdbcType=INTEGER} )} </select>
- 修正后的测试代码:
// 从Spring容器获取Dao实例,不要直接new TestDao testDao = applicationContext.getBean(TestDao.class); Map<String, Object> params = new HashMap<>(); params.put("id", "testid"); params.put("name", "testname"); testDao.testSP(params); // 从Map中取出OUT参数结果 System.out.println(params.get("out0")); System.out.println(params.get("out1"));
方案2:用实体类作为参数载体(更贴合业务场景)
如果你还是想用Result类接收结果,可以把它作为入参传递给Mapper方法:
- 修改Mapper接口:
public interface TestDao { void testSP(@Param("id") String id, @Param("name") String name, @Param("result") Result result); }
- 修改XML映射文件:
<select id="testSP" statementType="CALLABLE"> {call testSP( #{id, mode=IN, jdbcType=VARCHAR}, #{name, mode=IN, jdbcType=VARCHAR}, #{result.out0, mode=OUT, jdbcType=INTEGER}, #{result.out1, mode=OUT, jdbcType=INTEGER} )} </select>
- 修正后的测试代码:
TestDao testDao = applicationContext.getBean(TestDao.class); Result result = new Result(); testDao.testSP("testid", "testname", result); System.out.println(result.getOut0()); System.out.println(result.getOut1());
方案3:用注解简化配置(无需XML)
如果不想写XML,直接用MyBatis注解实现:
- 修改Mapper接口:
public interface TestDao { @Select("{call testSP(#{id, mode=IN, jdbcType=VARCHAR}, #{name, mode=IN, jdbcType=VARCHAR}, #{out0, mode=OUT, jdbcType=INTEGER}, #{out1, mode=OUT, jdbcType=INTEGER})}") @Options(statementType = StatementType.CALLABLE) void testSP(Map<String, Object> params); }
测试代码和方案1一致即可。
额外提醒
- 命名规范:Java里类名、接口名要遵循大驼峰(比如
TestDao、Result),变量名用小驼峰,这能避免很多潜在的语法或框架识别问题。 - 参数类型匹配:你存储过程的IN参数是
TEXT类型,MyBatis里用jdbcType=VARCHAR没问题,如果是超长文本可以改成jdbcType=LONGVARCHAR。
内容的提问来源于stack exchange,提问作者H.Y
相关产品推荐
相关产品推荐

