1.概述

转载:核心配置综述之 ParameterHandler

MyBatis 四大核心组件我们已经了解到了两种,一个是 Executor ,它是MyBatis 解析SQL请求首先会经过的第一道关卡,它的主要作用在于创建缓存,管理 StatementHandler 的调用,为 StatementHandler 提供 Configuration 环境等。

StatementHandler 组件最主要的作用在于创建 Statement 对象与数据库进行交流,还会使用 ParameterHandler 进行参数配置,使用 ResultSetHandler 把查询结果与实体类进行绑定。那么本篇就来了解一下第三个组件 ParameterHandler。

2.ParameterHandler 简介

ParameterHandler 相比于其他的组件就简单很多了,ParameterHandler 译为参数处理器,负责为 PreparedStatement 的 sql 语句参数动态赋值,这个接口很简单只有两个方法

/*** A parameter handler sets the parameters of the {@code PreparedStatement}* 参数处理器为 PreparedStatement 设置参数*/
public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps)throws SQLException;}

ParameterHandler 只有一个实现类 DefaultParameterHandler , 它实现了这两个方法。

getParameterObject: 用于读取参数
setParameters: 用于对 PreparedStatement 的参数赋值

3.ParameterHandler 创建

参数处理器对象是在创建 StatementHandler 对象的同时被创建的,由 Configuration 对象负责创建

BaseStatementHandler.java

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {this.configuration = mappedStatement.getConfiguration();this.executor = executor;this.mappedStatement = mappedStatement;this.rowBounds = rowBounds;this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.objectFactory = configuration.getObjectFactory();if (boundSql == null) { // issue #435, get the key before calculating the statementgenerateKeys(parameterObject);boundSql = mappedStatement.getBoundSql(parameterObject);}this.boundSql = boundSql;// 创建参数处理器this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);// 创建结果映射器this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

在创建 ParameterHandler 时,需要传入SQL的mappedStatement 对象,读取的参数和SQL语句

注意:一个 BoundSql 对象,就代表了一次sql语句的实际执行,而 SqlSource 对象的责任,就是根据传入的参数对象,动态计算这个 BoundSql, 也就是 Mapper 文件中节点的计算,是由 SqlSource 完成的,SqlSource 最常用的实现类是 DynamicSqlSource

Configuration.java

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {// 创建ParameterHandlerParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;
}

上面是 Configuration 创建 ParameterHandler 的过程,它实际上是交由 LanguageDriver 来创建具体的参数处理器,LanguageDriver 默认的实现类是 XMLLanguageDriver,由它调用 DefaultParameterHandler 中的构造方法完成 ParameterHandler 的创建工作

public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {this.mappedStatement = mappedStatement;this.configuration = mappedStatement.getConfiguration();// 获取 TypeHandlerRegistry 注册this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();this.parameterObject = parameterObject;this.boundSql = boundSql;
}

上面的流程是创建 ParameterHandler 的过程,创建完成之后,该进行具体的解析工作,那么 ParameterHandler 如何解析SQL中的参数呢?SQL中的参数从哪里来的?

4.ParameterHandler 中的参数从何而来

你可能知道 Parameter 中的参数是怎么来的,无非就是从 Mapper 配置文件中映射过去的啊,就比如如下例子


参数肯定就是图中标红的 1 ,然后再传到XML对应的 SQL 语句中,用 #{} 或者 ${} 来进行赋值啊,


嗯,你讲的没错,可是你知道这个参数是如何映射过来的吗?或者说你知道 Parameter 的解析过程吗?或许你不是很清晰了,我们下面就来探讨一下 ParameterHandler 对参数的解析,这其中涉及到 MyBatis 中的动态代理模式

在MyBatis 中,当 deptDao.findByDeptNo(1) 将要执行的时候,会被 JVM 进行拦截,交给 MyBatis 中的代理实现类 MapperProxy 的 invoke 方法中,这也是执行 SQL 语句的主流程。


然后交给 Executor 、StatementHandler进行对应的参数解析和执行,因为是带参数的 SQL 语句,最终会创建 PreparedStatement 对象并创建参数解析器进行参数解析

SimpleExecutor.java


handler.parameterize(stmt) 最终会调用到 DefaultParameterHandler 中的 setParameters 方法,我在源码上做了注释,为了方便拷贝,我没有采用截图的形式

public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// parameterMappings 就是对 #{} 或者 ${} 里面参数的封装List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {// 如果是参数化的SQL,便需要循环取出并设置参数的值for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);// 如果参数类型不是 OUT ,这个类型与 CallableStatementHandler 有关// 因为存储过程不存在输出参数,所以参数不是输出参数的时候,就需要设置。if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;// 得到#{}  中的属性名String propertyName = parameterMapping.getProperty();// 如果 propertyName 是 Map 中的keyif (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params// 通过key 来得到 additionalParameter 中的value值value = boundSql.getAdditionalParameter(propertyName);}// 如果不是 additionalParameters 中的key,而且传入参数是 null, 则value 就是nullelse if (parameterObject == null) {value = null;}// 如果 typeHandlerRegistry 中已经注册了这个参数的 Class对象,即它是Primitive 或者是String 的话else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {// 否则就是 MapMetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}// 在通过SqlSource 的parse 方法得到parameterMappings 的具体实现中,我们会得到parameterMappings的typeHandlerTypeHandler typeHandler = parameterMapping.getTypeHandler();// 获取typeHandler 的jdbc typeJdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);} catch (SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}}
}

5.ParameterHandler 解析

我们在 MyBatis 核心配置综述之 StatementHandler 一文中了解到 Executor 管理的是 StatementHandler 对象的创建以及参数赋值,那么我们的主要入口还是 Executor 执行器

下面用一个流程图表示一下 ParameterHandler 的解析过程,以简单执行器为例


像是 doQuery,doUpdate,doQueryCursor等方法都会先调用到

// 生成 preparedStatement 并调用 prepare 方法,并为参数赋值
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;Connection connection = getConnection(statementLog);stmt = handler.prepare(connection, transaction.getTimeout());handler.parameterize(stmt);return stmt;
}

然后在生成 preparedStatement 调用DefaultParameterHandler进行参数赋值。

【MyBatis】MyBatis 核心配置综述之 ParameterHandler相关推荐

  1. 第七章 MyBatis的核心配置

    单选题 1.关于MyBatis配置文件中元素说法错误的是()2分 A.可以通过在MyBaits中配置元素来定义别名 B.MyBaits配置文件中元素的子元素需要配置type和alias属性 C.可以通 ...

  2. MyBatis 核心配置综述之 Configuration详解

    颓废青年,快出来挨打! 点击上方"Java极客技术",选择"设为星标" 后台回复"java",获取Java知识体系/面试必看资料 资料会持续 ...

  3. mybatis核心配置_MyBatis 核心配置综述之StatementHandler

    StatementHandler 是四大组件中最重要的一个对象,负责操作 Statement 对象与数据库进行交流,在工作时还会使用 ParameterHandler 和 ResultSetHandl ...

  4. MyBatis简介与配置

    一.MyBatis简介与配置MyBatis+Spring+MySql MyBatis学习 之 一.MyBatis简介与配置MyBatis+Spring+MySql MyBatis学习 之 二.SQL语 ...

  5. Mybatis学习之配置优化

    前言 接上章学习,我们配置build了之后,成功解决了资源导出失败的问题,这章我们学习的是配置优化 一.原来的配置 1.数据库配置(属性优化) 原先写死的数据库核心配置 <!--核心配置文件-- ...

  6. MyBatis(一)MyBatis介绍和配置详解

    在Java程序里面去操作数据库,最原始的办法是使用JDBC的API.需要分为六步: 注册驱动 通过DriverManager获取一个Connection 通过Connection创建一个Stateme ...

  7. MyBatis四大核心概念

    本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder.SqlSessionFactory.SqlSession.Mapper). MyBatis 作为互联网数据库映 ...

  8. SpringBoot 精通系列-如何优雅地使用Mybatis的XML配置

    导语   首先Mybatis作为如今最为流行的ORM框架之一,那么首先需要了解的就是什么是ORM框架. 文章目录 ORM框架 为什么需要ORM这种技术呢? Mybatis简介 Mybatis的几个重要 ...

  9. 第一章:ORM框架发展历程和MyBatis的核心应用

    ORM框架的发展历史与MyBatis的高级应用 一.ORM框架的发展历程 1. JDBC操作 1.1 JDBC操作的特点 最初的时候我们肯定是直接通过jdbc来直接操作数据库的,本地数据库我们有一张t ...

最新文章

  1. 亏损数亿,阿里也要强推99元白菜价智能音箱!背后逻辑到底是啥?
  2. ACMNO.47 矩形面积交(有图) 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。
  3. 数学建模学习笔记——预测模型
  4. SpringCloud实战4-Hystrix线程隔离请求缓存请求合并
  5. ECCV 2020 亮点摘要(上)
  6. 【转】PHP面试题总结
  7. Spark-Streaming
  8. XMLHTTP使用详解
  9. linux ubuntu 加密狗,ubuntu – 将usb加密狗连接到KVM VM
  10. 论文阅读:Audio-Driven Emotional Video Portraits
  11. ecos kernel 分析 转自黑嘴公 PiPi Cat
  12. springMVC 415 错误
  13. adb连接网易mumu模拟器
  14. emule中节点加入Kad网络过程(源代码详解)
  15. android 后台运行清理,【Android】App在后台被清理后的终极应对手段——重启应用...
  16. 得到app文稿导出_逻辑思维,阅读付费平台“得到APP”功能分析
  17. 008九九乘法表(详解)
  18. 【Fastlio2 SLAM算法实现】
  19. ngx-datatable的使用
  20. 全球首款18GB RAM手机:腾讯ROG游戏手机5发布

热门文章

  1. 十分钟看懂图像语义分割技术(转载)
  2. Android音频简介
  3. 串口调试助手vc源程序及其详细编写过程
  4. Pygame入门 2022 (4) 使用精灵类重构
  5. W32Dasm反汇编工具使用教程
  6. 德国著名的五位数学家
  7. 【随记】win10,系统,任务栏--工具栏--桌面,存在两个“控制面板”
  8. 罗斯蒙特3051常见故障解决方案
  9. 第五届全国现代物流绿色包装与循环共用大会线上成功举办
  10. Kotlin 自学笔记