Mybatis--调用存储过程接收存储过程返回的多结果集以及出参参数接收

来源于  https://blog.csdn.net/piglite/article/details/132724658

有时候在程序开发中,需要用到存储过程,这里讲解了在Springboot的项目下,Mybatis如何调用存储过程,以及接收存储过程返回的多个结果集

Exam表结构

  1.  
    SET NAMES utf8mb4;
  2.  
    SET FOREIGN_KEY_CHECKS = 0;
  3.  
     
  4.  
    -- ----------------------------
  5.  
    -- Table structure for exam
  6.  
    -- ----------------------------
  7.  
    DROP TABLE IF EXISTS `exam`;
  8.  
    CREATE TABLE `exam`  (
  9.  
      `ID` int(11) NOT NULL AUTO_INCREMENT,
  10.  
      `ordernum` int(11) NULL DEFAULT NULL,
  11.  
      `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
  12.  
      `starttime` datetime(0) NULL DEFAULT NULL,
  13.  
      `endtime` datetime(0) NULL DEFAULT NULL ,
  14.  
      `createtime` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0),
  15.  
      `passfs` decimal(6, 2) NULL DEFAULT NULL ,
  16.  
      `fscount` decimal(6, 2) NULL DEFAULT 0.00 ,
  17.  
      `timucount` int(11) NULL DEFAULT 0  ,
  18.  
      `isenabled` int(11) NULL DEFAULT NULL ,
  19.  
      `kaoshitime` int(11) NULL DEFAULT 0,
  20.  
      `ownerid` int(11) NULL DEFAULT NULL ,
  21.  
      `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  22.  
      `isck` int(3) NULL DEFAULT 1 ,
  23.  
      `cknum` int(11) NULL DEFAULT 0 ,
  24.  
      `examtype` int(3) NULL DEFAULT NULL ,
  25.  
      `istry` int(3) NULL DEFAULT 2 ,
  26.  
      `isbackup` int(3) NULL DEFAULT 0 ,
  27.  
      PRIMARY KEY (`ID`) USING BTREE
  28.  
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
  29.  
     
  30.  
    SET FOREIGN_KEY_CHECKS = 1;

Jigou表结构

  1.  
    SET NAMES utf8mb4;
  2.  
    SET FOREIGN_KEY_CHECKS = 0;
  3.  
     
  4.  
    -- ----------------------------
  5.  
    -- Table structure for jigou
  6.  
    -- ----------------------------
  7.  
    DROP TABLE IF EXISTS `jigou`;
  8.  
    CREATE TABLE `jigou`  (
  9.  
      `ID` int(11) NOT NULL AUTO_INCREMENT,
  10.  
      `jgname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  11.  
      `address` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  12.  
      `lxname` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  13.  
      `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  14.  
      `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  15.  
      PRIMARY KEY (`ID`) USING BTREE
  16.  
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  17.  
     
  18.  
    SET FOREIGN_KEY_CHECKS = 1;

写一个简单的测试用的存储过程,这个存储过程有一个入参,还有一个出参,并且还会返回两个结果集

  1.  
    CREATE DEFINER=`root`@`localhost` PROCEDURE `mytest`(IN in_ownerid INT,OUT examcount INT)
  2.  
    BEGIN
  3.  
     
  4.  
    select * from exam where ownerid=in_ownerid ;
  5.  
     
  6.  
    select count(*)  into examcount from exam where ownerid=in_ownerid;
  7.  
     
  8.  
    select * from jigou;
  9.  
     
  10.  
    END

TestMapper.java

  1.  
    @Repository
  2.  
    public interface TestMapper {
  3.  
     
  4.  
        List<List<?>> protest(Map<String,Object> map);
  5.  
    }

TestMapper.xml

  1.  
    <?xml version="1.0" encoding="UTF-8" ?>
  2.  
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3.  
    <mapper namespace="com.model.proceduredemo.dao.TestMapper">
  4.  
        <resultMap id="ExamMap" type="com.model.proceduredemo.Pojo.Exam" >
  5.  
            <id column="ID" property="id" jdbcType="INTEGER" />
  6.  
            <result column="ordernum" property="ordernum" jdbcType="INTEGER" />
  7.  
            <result column="name" property="name" jdbcType="VARCHAR" />
  8.  
            <result column="starttime" property="starttime" jdbcType="TIMESTAMP" />
  9.  
            <result column="endtime" property="endtime" jdbcType="TIMESTAMP" />
  10.  
            <result column="createtime" property="createtime" jdbcType="TIMESTAMP" />
  11.  
            <result column="passfs" property="passfs" jdbcType="DECIMAL" />
  12.  
            <result column="fscount" property="fscount" jdbcType="DECIMAL" />
  13.  
            <result column="timucount" property="timucount" jdbcType="INTEGER" />
  14.  
            <result column="isenabled" property="isenabled" jdbcType="INTEGER" />
  15.  
            <result column="kaoshitime" property="kaoshitime" jdbcType="INTEGER" />
  16.  
            <result column="ownerid" property="ownerid" jdbcType="INTEGER" />
  17.  
            <result column="password" property="password" jdbcType="VARCHAR" />
  18.  
            <result column="isck" property="isck" jdbcType="INTEGER" />
  19.  
            <result column="cknum" property="cknum" jdbcType="INTEGER" />
  20.  
            <result column="examtype" property="examtype" jdbcType="INTEGER" />
  21.  
            <result column="istry" property="istry" jdbcType="INTEGER" />
  22.  
            <result column="isbackup" property="isbackup" jdbcType="INTEGER" />
  23.  
        </resultMap>
  24.  
     
  25.  
        <resultMap id="JigouMap" type="com.model.proceduredemo.Pojo.Jigou" >
  26.  
            <id column="ID" property="id" jdbcType="INTEGER" />
  27.  
            <result column="jgname" property="jgname" jdbcType="VARCHAR" />
  28.  
            <result column="address" property="address" jdbcType="VARCHAR" />
  29.  
            <result column="lxname" property="lxname" jdbcType="VARCHAR" />
  30.  
            <result column="phone" property="phone" jdbcType="VARCHAR" />
  31.  
            <result column="password" property="password" jdbcType="VARCHAR" />
  32.  
        </resultMap>
  33.  
        
  34.  
        <select id="protest"  resultMap="ExamMap,JigouMap"  parameterType="Map" 
  35.  
                                                         statementType="CALLABLE"  >
  36.  
              {CALL mytest(#{ownerid,mode=IN,jdbcType=INTEGER},#{examcount,mode=OUT,jdbcType=INTEGER})}
  37.  
        </select>
  38.  
    </mapper>

TestServiceImpl.java(TestService接口略)

  1.  
    @Service
  2.  
    public class TestServiceImpl implements TestService {
  3.  
     
  4.  
        @Autowired
  5.  
        private TestMapper testMapper;
  6.  
     
  7.  
        @Override
  8.  
        public void mytest() throws JsonProcessingException {
  9.  
            Map<String,Object> map=new HashMap<>();
  10.  
            map.put("ownerid",1);
  11.  
            List<List<?>>  list= testMapper.protest(map);
  12.  
            ObjectMapper objectMapper=new ObjectMapper();
  13.  
            System.out.println("结果集一:"+objectMapper.writeValueAsString(list.get(0)));
  14.  
            System.out.println("结果集二:"+objectMapper.writeValueAsString(list.get(1)));
  15.  
            System.out.println("出参参数值:"+map.get("examcount"));
  16.  
            return RetResponse.makeOkRsp(list);
  17.  
        }
  18.  
    }

MyController.java

  1.  
    @RestController
  2.  
    public class MyController {
  3.  
     
  4.  
        @Autowired
  5.  
        private TestService testService;
  6.  
        
  7.  
        @RequestMapping("/test")
  8.  
        public void test() throws JsonProcessingException {
  9.  
            testService.mytest();
  10.  
        }
  11.  
    }

请求的结果如下图所示(因为返回的查询结果转换成JSON字符串显示在控制台,字符串太长了这里只显示了部分):


拓展:
从上面可以看出,在Mapper.xml的映射文件定义了两个resultMap标签,是因为在这里存储过程返回了两个结果集,一个是根据入参参数查询exam表返回的查询结果,还有一个是查询Jigou表返回的查询结果,所以要写两个相应的resultMap标签来接收存储过程返回的结果集。

但是这样编写resultMap标签十分麻烦,因为要把JAVA对象里的属性和MySql表中的字段一一对应映射起来,所以接下来介绍一种简便的方法来接收返回的结果集

其他代码基本不变,只修改Mapper.xml映射文件TestMapper.xml

  1.  
    <?xml version="1.0" encoding="UTF-8" ?>
  2.  
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3.  
    <mapper namespace="com.model.proceduredemo.dao.TestMapper">
  4.  
     
  5.  
        <resultMap id="Map1" type="java.util.HashMap">
  6.  
        </resultMap>
  7.  
        
  8.  
        <resultMap id="Map2" type="java.util.HashMap">
  9.  
        </resultMap>
  10.  
        
  11.  
        <select id="protest"  resultMap="Map1,Map2"  parameterType="Map" 
  12.  
                                                    statementType="CALLABLE"  >
  13.  
          {CALL mytest(#{ownerid,mode=IN,jdbcType=INTEGER},
  14.  
                                              #{examcount,mode=OUT,jdbcType=INTEGER})}
  15.  
        </select>
  16.  
     
  17.  
     
  18.  
    </mapper>

然后测试查看结果:

结果没变化,只是字段的顺序产生了变化,因为HashMap类型是无序的。

由上可知,返回的结果集直接使用HashMap接收方便很多,不用进行JAVA对象属性跟Mysql表的字段映射

总结:
调用存储过程时,Mapper.xml映射文件中select标签中的statementType属性必须声明为CALLABLE
因为存储过程有出参和入参,所以在Mapper接口中参数最好使用Map<String,Object>类型,并且要在select标签中的parameterType属性声明为Map,因为这样不仅能够传入入参的参数,还能够获得出参的参数。
有几个结果集,那就定义几个resultMap标签来接收,然后在select标签中resultMap属性声明为上面定义的resultMap标签,多个之间用逗号分开并且在Mapper接口中把返回值声明为List<List<?>>的泛型来接收
(这里解释一下List<List<?>>类型,最外面的List表明有几个结果集,里面的List表明该结果集有多少条数据。最后里面这个?表示泛型,也就是用Object接收,如果采取拓展方法来接收结果集的话,那么这个?可以替换成Map<String,Object>)
在Mapper.xml映射文件中,调用存储过程时,参数名不用写的和存储过程定义的参数名一样,只要顺序对上即可。
 

 
posted @   苦行者的刀  阅读(981)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示