Mybatis源码解析6:Mapper执行流程2-三个Handler

Mybatis源码解析6:Mapper执行流程2-三个Handler

    • 1.项目结构
    • 2. 源码分析
      • 2.1 StatementHandler分析 BaseStatementHandler#prepare
      • 2.2 ParameterHandler分析 DefaultParameterHandler#setParameters
      • 2.3 ResultSetHandler分析

1.项目结构

2. 源码分析

之前已经对 SimpleExecutor#doQuery。StatementHandler是对Statement进行处理,ParameterHandler是对参数的设置进行处理,ResultSetHandler是对Statement执行的结果集进行处理

2.1 StatementHandler分析 BaseStatementHandler#prepare

  @Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement = null;try {statement = instantiateStatement(connection);setStatementTimeout(statement, transactionTimeout);setFetchSize(statement);return statement;} catch (SQLException e) {closeStatement(statement);throw e;} catch (Exception e) {closeStatement(statement);throw new ExecutorException("Error preparing statement.  Cause: " + e, e);}}
  1. 获取JDBC层次的Statement对象
  2. 设置Statement的超时时间

实例化Statement PreparedStatementHandler#instantiateStatement

  @Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql = boundSql.getSql();if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {String[] keyColumnNames = mappedStatement.getKeyColumns();if (keyColumnNames == null) {return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);} else {return connection.prepareStatement(sql, keyColumnNames);}} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {return connection.prepareStatement(sql);} else {return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}
  1. 获取到sql,此时的sql还没有设置参数。select id, name from blog where id = ?
  2. 用过Connection对象获取jdbc层次的Statement

2.2 ParameterHandler分析 DefaultParameterHandler#setParameters

  @Overridepublic void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional paramsvalue = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}TypeHandler typeHandler = parameterMapping.getTypeHandler();JdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException | SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}}}
  1. parameterMappings是Sql中的参数的信息,而parameterObject是参数所对应的值
  2. 通过configuration.newMetaObject(parameterObject)方法,对参数对象进行了封装,里面有反射工厂,会通过反射获取到get、set方法,并且取值和设置值
  3. 遍历parameterMappings通过参数的信息,获取到每个参数对应的值,并且获取到值所对应的类型转换器TypeHandler。TypeHandler是在全局配置Configuration中,可通过mybatis-config.xml配置。Configuration中已经默认了常用的类型转换器。
  4. 最终通过PreparedStatement设置参数
    在这里插入图片描述

2.3 ResultSetHandler分析

DefaultResultSetHandler#handleResultSets

  @Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<>();int resultSetCount = 0;ResultSetWrapper rsw = getFirstResultSet(stmt);List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {ResultMap resultMap = resultMaps.get(resultSetCount);handleResultSet(rsw, resultMap, multipleResults, null);rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}return collapseSingleResultList(multipleResults);}
  1. 获取JDBC的ResultSet,通过JDK代理ResultSetLogger,ResultSetWrapper封装ResultSetLogger和Configuration
  2. 获取resultMapCount条数据,一行一行地去处理结果集

DefaultResultSetHandler#handleResultSet

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping != null) {handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {if (resultHandler == null) {DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);multipleResults.add(defaultResultHandler.getResultList());} else {handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());}}

这里就是创建一个结果集处理器,然后解析数据,封装到对象里面

DefaultResultSetHandler#getRowValue


private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<>();ResultSet resultSet = rsw.getResultSet();skipRows(resultSet, rowBounds);while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);Object rowValue = getRowValue(rsw, discriminatedResultMap, null);storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);}
}private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {final ResultLoaderMap lazyLoader = new ResultLoaderMap();Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;if (shouldApplyAutomaticMappings(resultMap, false)) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;}foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue;}private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues = false;if (!autoMapping.isEmpty()) {for (UnMappedColumnAutoMapping mapping : autoMapping) {final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(mapping.property, value);}}}return foundValues;}
  1. 创建结果集对象,封装成元对象MetaObject
  2. 在applyAutomaticMappings里面遍历mapping,获取到mapping对应的结果值,设置到MetaObject里面
  3. 最终的结果集保存在DefaultResultHandler#list

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/219379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Scrapy爬虫学习

Scrapy爬虫学习一 1 scrapy框架1.1 scrapy 是什么1.2 安装scrapy 2 scrapy的使用2.1创建scrapy项目2.2 创建爬虫文件2.3爬虫文件的介绍2.4 运行爬虫文件 3 爬取当当网前十页数据3.1 dang.py&#xff1a;爬虫的主文件3.2 items.py 定义数据结构3.3 pipelines.py 管道3.4 执行命令…

总结了人工智能领域,能源领域,电气领域比较好中的一些sci期刊!!仅供参考

文章目录 前言一、总结了人工智能领域&#xff0c;能源领域&#xff0c;电气领域比较好中的一些sci期刊 总结 前言 期刊查询网站&#xff1a; https://www.letpub.com.cn/index.php?pagejournalapp&viewsearch 链接: 点我跳转期刊查询网站 一、总结了人工智能领域&#…

【Spring】02 Bean 的命名

文章目录 1. 定义2. 使用优势3. 如何命名4. 注解驱动5. 最佳实践1&#xff09;使用明确的业务名词2&#xff09;避免缩写和首字母缩略词2&#xff09;不要过度使用别名 结语 在 Spring 框架中&#xff0c;Bean 是应用程序中的主要组件&#xff0c;负责承载和管理应用的核心功能…

【python-wrf】绘制wrf中的土地利用报错内容及其解决方法

从该代码处绘制wrf中的土地利用报错内容及其解决方法 1.报错内容&#xff1a; 微信公众平台 (qq.com)https://mp.weixin.qq.com/s/Cn0vhvfroVADPnT237LXNw --------------------------------------------------------------------------- AttributeError …

mysql 字符串合并方法以及合并为null问题

concat()不推荐 mysql一般提供了两种一种是concat()函数一种是concat_ws()函数&#xff0c;前者合并字符串有个弊端&#xff0c;合并字段不能有null值&#xff0c; 否则如下图合并后会是null concat_ws()推荐 concat_ws()函数可以解决合并字符串为null问题&#xff0c;conca…

使用Microsoft Dynamics AX 2012 - 8. 财务管理

财务管理的主要职责是控制和分析与货币金额有关的所有交易。这些事务发生在整个组织的业务流程中。 因此&#xff0c;财务管理是企业管理解决方案的核心领域。在Dynamics AX中&#xff0c;支持所有部门业务流程的应用程序的深度集成可立即提供准确的财务数据。 分类账交易的原…

MySQL 中Relay Log打满磁盘问题的排查方案

MySQL 中Relay Log打满磁盘问题的排查方案 引言&#xff1a; MySQL Relay Log&#xff08;中继日志&#xff09;是MySQL复制过程中的一个重要组件&#xff0c;它用于将主数据库的二进制日志事件传递给从数据库。然而&#xff0c;当中继日志不断增长并最终占满磁盘空间时&…

实操Nginx(4层代理+7层代理)+Tomcat多实例部署,实现负载均衡和动静分离

目录 前言 一、tomcat多实例部署 步骤一&#xff1a;先安装jdk&#xff0c;设置jdk的环境变量&#xff0c;验证是否安装完成&#xff08;192.168.20.8&#xff09; 步骤二&#xff1a;安装tomcat&#xff08;192.168.20.18&#xff09; 步骤三&#xff1a;安装tomcat多实例…

快速上手linux | 一文秒懂Linux各种常用目录命令(上)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 一 、命令提示符和命令的基本格式1.1 如何查看主机名称及修改 二、命令基本格式2.1 命令格式示例2.2 参数的作用…

Spring Cloud gateway - CircuitBreaker GatewayFilte

前面学习Spring cloud gateway的时候&#xff0c;做测试的过程中我们发现&#xff0c;Spring Cloud Gateway不需要做多少配置就可以使用Spring Cloud LoadBalance的功能&#xff0c;比如&#xff1a; spring:application:name: spring-gatewaycloud:gateway:routes:- id: path…

ELK简单介绍二

学习目标 能够部署kibana并连接elasticsearch集群能够通过kibana查看elasticsearch索引信息知道用filebeat收集日志相对于logstash的优点能够安装filebeat能够使用filebeat收集日志并传输给logstash kibana kibana介绍 Kibana是一个开源的可视化平台,可以为ElasticSearch集群…

电子取证中Chrome各版本解密Cookies、LoginData账号密码、历史记录

文章目录 1.前置知识点2.对于80.X以前版本的解密拿masterkey的几种方法方法一 直接在目标机器运行Mimikatz提取方法二 转储lsass.exe 进程从内存提取masterkey方法三 导出SAM注册表 提取user hash 解密masterkey文件&#xff08;有点麻烦不太推荐&#xff09;方法四 已知用户密…

插入算法(C语言)

#include<cstdio> #include<iostream> #define N 9 using namespace std; int main() {int arr[N1] { 1,4,7,13,16,19,22,25,280 }; int in,i,j;//要插入的数字//打印要插入数字的数组所有元素printf("插入前的数组: ");for ( i 0; i <N; i){print…

STM32G030C8T6:使用外部晶振配置LED灯闪烁

本专栏记录STM32开发各个功能的详细过程&#xff0c;方便自己后续查看&#xff0c;当然也供正在入门STM32单片机的兄弟们参考&#xff1b; 本小节的目标是&#xff0c;使用STM32G030C8T6单片机&#xff0c;通过STM32CubeMX软件&#xff0c;配置并使用外部8MHz晶振&#xff0c;实…

6. Service详解

6. Service详解 文章目录 6. Service详解6.1 Service介绍6.2 Service类型6.3 Service使用6.3.1 实验环境准备6.3.2 ClusterIP类型的Service6.3.3 HeadLess类型的Service6.3.3.1 deployment和statefulset区别6.3.3.2 statefulset deployment 区别 6.3.4 NodePort类型的Service6.…

扩展操作码指令格式

指令 操作码地址码 \quad \quad 判断几地址指令 开头4位不是全1, 则表示是三地址指令 开头4位全1, 后面4位不是全1, 则为二地址指令 前面12全1, 则为零地址指令 当然啦这只是一种扩展方法, 如果想扩展更多, 可以将1110留作扩展操作码 较短的操作码, 我们对它的译码和分析的时间…

点云几何 之 判断某一点是否在三角形的边上(3)

点云几何 之 判断某一点是否在三角形的边上&#xff08;3&#xff09; 一、算法介绍二、算法实现1.代码2.结果 总结 一、算法介绍 判断某一点是否在三角形的边上 之前已经介绍了点在三角形的内外判断方法&#xff0c;这里增加点恰好在三角形边上的判断方法 &#xff08;本质上…

节流防抖:提升前端性能的秘密武器(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

vue3使用mars3d实现地图轮播高亮,且每个区域颜色不一样

效果图(珙县就是轮播高亮的效果) 思路:初始化一张完整的地图&#xff0c;然后定时器去挨个生成每个县上的地图&#xff0c;并且覆盖在原来的位置&#xff0c;每到一定的时间&#xff0c;就清除之前生成高亮图并且生成下一张高亮图 如何引入地图 上篇文章已详细发过 略 父组…