前言在实际企业开发中经常会遇到使用存储过程处理复杂业务逻辑的场景比如多表联查、数据统计、事务性批量操作。MyBatis 作为主流的 ORM 框架完美支持存储过程调用但很多新手对如何接收存储过程的 OUT/INOUT 输出参数感到困惑。本文将从存储过程编写、MyBatis 配置、参数接收、实战案例全流程讲解带你彻底掌握 MyBatis 接收存储过程 OUTPUT 参数的方法。一、核心知识点MyBatis 调用存储过程使用标签select/update/insert必须指定statementTypeCALLABLE存储过程参数模式IN入参默认OUT出参MyBatis 需要显式声明接收INOUT既入参又出参接收 OUT 参数使用modeOUTjdbcType指定数据库类型参数接收方式Map 集合/实体类两种方案二、环境准备MySQL 数据库本文以 MySQL 为例Oracle/Others 同理SpringBoot MyBatis 环境测试表示例sqlCREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, age INT );三、编写 MySQL 存储过程我们创建一个带 IN 入参 OUT 出参的存储过程输入用户 ID输出用户名、年龄、统计结果sql-- 创建存储过程 DELIMITER // -- 定义结束符 CREATE PROCEDURE proc_get_user_info( IN p_user_id INT, -- 入参用户ID OUT pJAVAMyBatis 调用存储过程接收 OUTPUT 输出参数Java 完整实战在 Java 企业开发中MyBatis 调用数据库存储过程接收 OUT/INOUT 输出参数是高频场景本文基于纯 Java MyBatis环境从零到一实现存储过程调用、输出参数接收包含 MySQL 存储过程编写、Mapper 接口、XML 配置、Java 测试全流程代码可直接复制运行。一、核心要点必看MyBatis 调用存储过程必须配置statementTypeCALLABLE输出参数用modeOUT声明必须指定jdbcTypeJava 接收方式实体类/Map 集合推荐实体类更规范存储过程执行后输出参数会自动回写到入参对象中二、环境准备MySQL 5.7/8.0MyBatis 3.xJDK 1.8测试表sqlCREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(50) NOT NULL COMMENT 用户名, age INT COMMENT 年龄 ); -- 插入测试数据 INSERT INTO user(username, age) VALUES (张三, 22), (李四, 25);三、创建 MySQL 存储过程带 IN/OUT 参数创建一个根据用户 ID 查询信息并返回输出参数的存储过程入参p_id用户 ID出参p_username用户名、p_age年龄、p_msg执行提示sql-- 创建存储过程 DELIMITER // CREATE PROCEDURE proc_get_user( IN p_id INT, -- 入参用户ID OUT p_username VARCHAR(50), -- 出参用户名 OUT p_age INT, -- 出参年龄 OUT p_msg VARCHAR(100) -- 出参执行结果 ) BEGIN -- 查询用户数据赋值给输出参数 SELECT username, age INTO p_username, p_age FROM user WHERE id p_id; -- 判断是否查询到数据 IF p_username IS NOT NULL THEN SET p_msg CONCAT(查询成功用户ID, p_id); ELSE SET p_msg CONCAT(用户ID, p_id, 不存在); SET p_age 0; END IF; END // DELIMITER ;四、Java 代码实现1. 实体类接收输入 / 输出参数用于封装入参和出参存储过程执行后输出参数会自动赋值到该对象java运行/** * 用户参数实体接收存储过程IN/OUT参数 */ public class UserParam { // 入参用户ID private Integer id; // 出参用户名 private String username; // 出参年龄 private Integer age; // 出参执行结果信息 private String msg; // getter/setter 必须写MyBatis需要反射赋值 public Integer getId() {return id;} public void setId(Integer id) {this.id id;} public String getUsername() {return username;} public void setUsername(String username) {this.username username;} public Integer getAge() {return age;} public void setAge(Integer age) {this.age age;} public String getMsg() {return msg;} public void setMsg(String msg) {this.msg msg;} // 重写toString方便打印结果 Override public String toString() { return UserParam{ id id , username username \ , age age , msg msg \ }; } }2. Mapper 接口定义调用方法java运行import org.apache.ibatis.annotations.Param; public interface UserMapper { /** * 调用存储过程接收OUT输出参数 * param userParam 入参出参封装对象 */ void callUserProc(UserParam userParam); }3. MyBatis XML 映射文件核心配置关键statementTypeCALLABLEmodeOUT声明输出参数xml?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd !-- 对应Mapper接口全路径 -- mapper namespacecom.mapper.UserMapper !-- 调用存储过程接收OUT参数 -- select idcallUserProc statementTypeCALLABLE parameterTypecom.entity.UserParam { CALL proc_get_user( #{id, modeIN, jdbcTypeINTEGER}, #{username, modeOUT, jdbcTypeVARCHAR}, #{age, modeOUT, jdbcTypeINTEGER}, #{msg, modeOUT, jdbcTypeVARCHAR} ) } /select /mapper4. Java 测试代码调用 接收结果直接运行即可获取存储过程的OUT 输出参数java运行import com.entity.UserParam; import com.mapper.UserMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class ProcTest { public static void main(String[] args) throws IOException { // 1. 加载MyBatis配置文件 String resource mybatis-config.xml; InputStream inputStream Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream); // 2. 获取SqlSession try (SqlSession session sqlSessionFactory.openSession()) { // 3. 获取Mapper接口 UserMapper userMapper session.getMapper(UserMapper.class); // 4. 封装入参 UserParam param new UserParam(); param.setId(1); // 查询ID1的用户 // 5. 调用存储过程执行后输出参数自动回写到param对象中 userMapper.callUserProc(param); // 6. 接收并打印OUT输出参数 System.out.println(存储过程执行结果); System.out.println(用户名 param.getUsername()); System.out.println(年龄 param.getAge()); System.out.println(执行信息 param.getMsg()); System.out.println(完整对象 param); } } }五、执行结果plaintext存储过程执行结果 用户名张三 年龄22 执行信息查询成功用户ID1 完整对象UserParam{id1, username张三, age22, msg查询成功用户ID1}六、进阶Map 接收 OUT 参数简化版如果不想创建实体类可直接用Map接收无需定义实体1. Mapper 接口java运行void callUserProcMap(MapString, Object paramMap);2. XML 配置xmlselect idcallUserProcMap statementTypeCALLABLE parameterTypemap { CALL proc_get_user( #{id, modeIN, jdbcTypeINTEGER}, #{username, modeOUT, jdbcTypeVARCHAR}, #{age, modeOUT, jdbcTypeINTEGER}, #{msg, modeOUT, jdbcTypeVARCHAR} ) } /select3. Java 测试java运行MapString, Object paramMap new HashMap(); paramMap.put(id, 1); userMapper.callUserProcMap(paramMap); // 接收OUT参数 System.out.println(用户名 paramMap.get(username)); System.out.println(执行信息 paramMap.get(msg));七、常见坑避坑指南必须加statementTypeCALLABLE否则 MyBatis 会把存储过程当普通 SQL 执行报错OUT 参数必须指定jdbcType不指定会报类型不匹配错误参数顺序必须和存储过程一致入参、出参顺序不能乱输出参数自动回写无需接收返回值直接从入参对象 / Map 中取Oracle 注意输出参数游标需指定jdbcTypeCURSORjavaTypeResultSet八、总结MyBatis 调用存储过程核心statementTypeCALLABLE接收 OUT 参数modeOUTjdbcTypeJava 接收方案实体类规范/Map简洁执行后输出参数自动回写到入参对象直接取值即可