【源码解析】MyBatis 结果集映射和参数绑定

本文深入解析MyBatis结果集映射的源码,详细阐述了DefaultResultSetHandler如何处理ResultSet,包括handleRowValuesForSimpleResultMap()方法的核心步骤:预处理、确定ResultMap、创建映射对象、自动映射、正常映射和存储映射结果对象。
摘要由CSDN通过智能技术生成

前言

:mailbox: 作者简介 :小明java问道之路,专注于研究计算机底层/Java/Liunx 内核,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计:mailbox: 

:trophy: InfoQ 签约博主 、CSDN 专家博主/Java 领域优质创作者、阿里云专家/签约博主、华为云专家、51CTO 专家 :trophy:

:fire:如果此文还不错的话,还请:+1: 关注 、点赞 、收藏 三连支持:+1:一下博主~

本文导读

本文讲解 MyBatis 结果集映射源码解析,详细分析了 handleRowValuesForSimpleResultMap() 等方法实现映射的核心步骤。

MyBatis 结果集映射是在 MyBatis 解析 Mapper.xml 映射文件的过程中, <resultMap> 标签会被解析成 ResultMap 对象的,当 MyBatis 执行完一条 select 语句, 拿到 ResultSet 结果集之后,会将其交给关联的 ResultSetHandler 进行后续的映射处理 。ResultSetHandler 其中定义了三个方法,分别用来处理不同的查询返回值, MyBatis 中只提供了一个 ResultSetHandler 接口实现,即 DefaultResultSetHandler。

ResultSetHandler 接口以及 DefaultResultSetHandler 这个默认实现,其中单个结果集映射的入口在 handleResultSets() 方法。handleRowValuesForSimpleResultMap() 方法实现简单映射的核心步骤,其中涉及 预处理 ResultSet、查找并确定 ResultMap、创建并填充映射结果对象、自动映射、正常映射、存储映射结果对象这六大核心步骤。

public interface ResultSetHandler {
      // 将ResultSet映射成Java对象    <E> List<E> handleResultSets(Statement stmt) throws SQLException;    // 将ResultSet映射成游标对象    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;    // 处理存储过程的输出参数    void handleOutputParameters(CallableStatement cs) throws SQLException;}

复制代码

​ 一、映射流程

​结果集处理入口

DefaultResultSetHandler 实现 handleResultSets() 方法,支持一个或多个 ResultSet 的处理。org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets。

遍历多结果集时使用到的 getFirstResultSet() 方法和 getNextResultSet() 方法,这两个方法底层都是检测是否存在后续的 ResultSet 对象,检测成功之后,会通过 getResultSet() 方法获取下一个 ResultSet 对象。这里获取到的 ResultSet 对象,会被包装成 ResultSetWrapper 对象返回。

ResultSetWrapper 主要用于封装 ResultSet 的一些元数据,其中记录了 ResultSet 中每列的名称、对应的 Java 类型、JdbcType 类型以及每列对应的 TypeHandler。ResultSetWrapper 可以将底层 ResultSet 的列与一个 ResultMap 映射的列进行交集,得到参与映射的列和未被映射的列,分别记录到 mappedColumnNamesMap 集合和 unMappedColumnNamesMap 集合中。这两个集合都是 Map<String, List<String>> 类型,其中最外层的 Key 是 ResultMap 的 id,Value 分别是参与映射的列名集合和未被映射的列名集合。

public List<Object> handleResultSets(Statement stmt) throws SQLException {
      // 用于记录每个ResultSet映射出来的Java对象    final List<Object> multipleResults = new ArrayList<>();    int resultSetCount = 0;
    // 从Statement中获取第一个ResultSet,其中对不同的数据库有兼容处理逻辑,    // 这里拿到的ResultSet会被封装成ResultSetWrapper对象返回    ResultSetWrapper rsw = getFirstResultSet(stmt);
    // 获取这条SQL语句关联的全部ResultMap规则。如果一条SQL语句能够产生多个ResultSet,    // 那么在编写Mapper.xml映射文件的时候,我们可以在SQL标签的resultMap属性中配置多个    // <resultMap>标签的id,它们之间通过","分隔,实现对多个结果集的映射    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();    validateResultMapsCount(rsw, resultMapCount);    while (rsw != null && resultMapCount > resultSetCount) { // 遍历ResultMap集合        ResultMap resultMap = resultMaps.get(resultSetCount);
        // 根据ResultMap中定义的映射规则处理ResultSet,并将映射得到的Java对象添加到        // multipleResults集合中保存        handleResultSet(rsw, resultMap, multipleResults, null);
        // 获取下一个ResultSet        rsw = getNextResultSet(stmt);
        // 清理nestedResultObjects集合,这个集合是用来存储中间数据的        cleanUpAft
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值