• Mybatis 中 ResultHandler 的用法(获取大结果集,实现结果流式输出)


      Mybatis 是一款优秀的 ORM 框架,它能够帮助程序员快速、简单地完成 Java 对象与关系数据库的互相映射。它提供了各种查询方式,其中一种比较有特色的查询方式就是使用 ResultHandler 进行查询,实现结果流式输出。

      有一种场景,查询结果有上百万条数据,如果在查询时把整个结果集一次性查询得到,存储于 List 返回的话,很可能会因为结果集太大,导致内存溢出(OOM)。此时我们可以采用分页查询或者可以利用 Mybatis 中的 ResultHandler 来实现流式输出。

      ResultHandler 接口只有一个方法 handleResult,我们可以实现这个方法去处理每一条 SQL 查询返回的数据。下面将详细介绍 Mybatis 中 ResultHandler 的用法。

    一、ResultHandler 简介

      Mybatis 中的 ResultHandler 相当于数据结果集的处理器,它是一个回调函数(Callback),用来处理每一行数据的结果,这个回调函数可以在查询结果处理到一定量时触发,对结果集数据进行定制化处理。

      ResultHandler 的使用可以大幅提升数据处理的效率,当我们需要处理大量的数据时,一般会使用 ResultHandler 来进行结果的处理,避免一次查询就全部返回结果,浪费内存资源或造成 OOM。

    二、ResultHandler 实现结果流式输出(两种写法)
    2.1 创建 TestResultHandler 类,实现 ResultHandler 接口

      创建 TestResultHandler 类,实现 ResultHandler 接口,重写 handleResult 方法,实现具体的业务逻辑,例如简单的打印或输出到文件等。其中,TblTestUser 是映射数据库表格的实体类。
      或者不创建该类,在查询时直接创建 ResultHandler 类,具体见 2.4 小节中的两种服务层写法。

    package com.test.handler;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.session.ResultContext;
    import org.apache.ibatis.session.ResultHandler;
    import com.test.model.TblTestUser;
    
    @Slf4j
    public class TestResultHandler implements ResultHandler<TblTestUser> {
    
        @Override
        public void handleResult(ResultContext<? extends TblTestUser> resultContext) {
            TblTestUser tblTestUser = resultContext.getResultObject();
    
            // 处理数据的逻辑
            try {
                // 打印每行日志
                log.info("userNo : [{}]", tblTestUser.getUserNo());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    2.2 TblTestUserMapper 接口,定义查询方法
    package com.test.dao;
    
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.session.ResultHandler;
    
    public interface TblTestUserMapper {
    
    	// SQL 返回值为 void,所以我们并没有接收这个返回值。所以不会产生大对象
    	// 方法中的第一个参数是查询时的限制条件,第二个是结果处理器
        void selectByResultHandler(@Param(value = "actNo") String actNo,
                                   ResultHandler resultHandler);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    2.3 XML 语法

      xml 查询方法和常规查询方法写法一致。

      <select id="selectByResultHandler" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List" />
        FROM tbl_test_user
      select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.4 服务层写法
    package com.test.service;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.session.ResultContext;
    import org.apache.ibatis.session.ResultHandler;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    import com.test.dao.TblTestUserMapper;
    import com.test.model.TblTestUser;
    
    import javax.annotation.Resource;
    
    @Service
    @Slf4j
    public class TestService {
    
        @Resource
        private TblTestUserMapper tblTestUserMapper;
    
        /**
         * 写法 1
         *
         * @param actNo 筛选条件:活动号
         */
        @Async
        public void test1(String actNo) {
            log.info("ResultHandler1 处理查询结果");
            TestResultHandler testResultHandler = new TestResultHandler();
            tblTestUserMapper.selectByResultHandler(actNo, testResultHandler);
        }
    
        /**
         * 写法 2
         *
         * @param actNo 筛选条件:活动号
         */
        @Async
        public void test2(String actNo) {
            log.info("ResultHandler2 处理查询结果");
            tblTestUserMapper.selectByResultHandler(actNo, new ResultHandler<TblTestUser>() {
                @Override
                public void handleResult(ResultContext<? extends TblTestUser> resultContext) {
                    TblTestUser tblTestUser = resultContext.getResultObject();
    
                    // 处理数据的逻辑
                    try {
                        // 打印每行日志
                        log.info("userNo : [{}]", tblTestUser.getUserNo());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
  • 相关阅读:
    simpleitk 读数据 图像 dicom nii 处理数据
    硬实力+软实力!2023功能测试进阶之路!
    从REST到GraphQL:升级你的Apollo体验
    C++ STL库的介绍和使用
    SpringCloud-alibaba-Sentinel入门到精通
    站外引流之道:跨境电商如何吸引更多流量?
    Linux性能模拟测试
    数据库设计-----理论
    【数据库】实验五 数据库综合查询|多表查询、聚集函数、orderby、groupby
    推荐5个神仙软件,个个让你爱不释手
  • 原文地址:https://blog.csdn.net/piaoranyuji/article/details/132884593