目录

  • 概念
    • 职责
    • 类图
  • 源码
    • ParameterHandler对象创建
    • ParameterHandler解析参数
  • 总结

概念

职责

ParameterHandler是用来设置参数规则的。StatementHandler中介绍到,其SimpleExecutor中调用prepare()方法之后,接下来StatementHandler就是使用parameterize来设置参数。以SampleExecutor为例,具体代码如下:

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;}@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}

类图

进入源码,该接口很简单,且只有一个默认实现类DefaultParameterHandler

public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps)throws SQLException;}
  • getParameterObject()用于读取参数;
  • setParameter():用于对PreparedStatementHandler的参数赋值;

源码

ParameterHandler对象创建

对于ParameterHandler对象的创建过程,首先抛出结论:该对象是在创建StatementHandler对象的同时被创建完成。StatementHandler文章中我们谈论到其依赖ParameterHandler和ResultSetHandler,下面我们进入正题。

上面谈到了该对象在StatementHandler对象创建时被创建,所以我们从StatementHandler对象位置开始跟踪:

  • SimpleExecutor
@Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();//Configuration中获取StatementHandler,跟进去StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}
  • Configuration
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {//创建StatementHandlerStatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}

跟进RoutingStatementHandler,我们以SimpleStatementHandler为例,其余*StatementHandler对象创建一样,调用其父类BaseStatementHandler构造方法,所以我们跟踪到其父类的构造方法中。

  • SimpleStatementHandler
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}
  • BaseStatementHandler
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 和resultSetHandler 对象的创建交给Configuration类操作;
从上面几步源码的跟踪:Configuration类依次完成了StatementHandler、parameterHandler 、resultSetHandler 对象的创建过程。
那么继续回归到Configuration中。

  • Configuration
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}

ParameterHandler解析参数

上面完成了StatementHandler,ParameterHandler和ResultSetHandler对象的创建,基本工作已准备完成,下面继续回归到SimpleExecutor#prepareStatement()

 @Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();//Configuration中获取StatementHandlerStatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//准备Statement对象stmt = prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}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;}
  • PrepareStatementHandler
@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}

代码里看到是parameterHandler对象调用,上面我们了解到ParameterHandler接口仅有一个实现类即DefaultParameterHandler,因此Debug进去。

  • DefaultParameterHandler
 @Overridepublic 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);} else if (parameterObject == null) {// 如果不是 additionalParameters 中的key,而且传入参数是 null, 则value 就是nullvalue = 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);}}}}}

总结

总结一下ParameterHandler整体大致流程走向,以下面时序图为例

Mybatis源码笔记之浅析ParameterHandler相关推荐

  1. Mybatis源码笔记之浅析StatementHandler

    目录 概述 职责 类图 源码 StatementHandler对象创建 总结 概述 职责 首先了解一下statementHandler职责:主要负责处理MyBatis与JDBC之间Statement的 ...

  2. 面试大厂被MyBatis问到“哑口无言”?这份MyBatis源码笔记助你吊打面试官!

    写在前面 随着手机.平板电脑等移动终端的广泛应用,移动互联网时代已经到来.在这个时代里,构建一个高效的平台并提供服务是移动互联网的基础,在众多的网站服务中,使用Java构建网站的不在少数,移动互联网的 ...

  3. mybatis源码深度解析_30天消化MyBatis源码解析笔记,吊打面试官,offer接到手软

    MyBatis 是一个优秀的 Java 持久化框架,SSM 框架组合(Spring + SpringMVC + Mybatis),依赖 MyBatis 搭建的项目更是数不胜数,在互联网公司的使用中,占 ...

  4. Mybatis源码学习笔记之Mybatis二级缓存

    简介   Mybatis一级缓存是会话级的缓存,而二级缓存则是应用级别的缓存,默认关闭,二级缓存使用不慎可能会导致脏读. 开启方式(SpringBoot+Mybatis)   application. ...

  5. MyBatis源码学习笔记(从设计模式看源码)

    文章目录 1.源码分析概述 ①.Mybatis架构分析 ②.门面模式 ③.设计模式的原则 2.日志模块分析 ①.适配器模型 ②.动态代理 ③.日志模块分析 3.数据源模块分析 ①.工厂模式 ②.数据源 ...

  6. mybatis源码-plugin源码

    在使用mybatis的时候,我们可以自己指定plugin,在sql执行过程中,增加一些额外的逻辑处理,这篇笔记主要记录plugin的原理 使用 1.声明自定义的plugin @Intercepts(@ ...

  7. 一周学完MyBatis源码,万字总结

    点击下方"IT牧场",选择"设为星标" 之前,我给大家分享给很多MyBatis源码分析的一系列文章.今天,就自己的感受来做一个整体的总结. 众所周知,MyBat ...

  8. Mybatis源码解读-设计模式总结

    虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...

  9. spring aop原理_Spring知识点总结!已整理成142页离线文档(源码笔记+思维导图)...

    写在前面 由于Spring家族的东西很多,一次性写完也不太现实.所以这一次先更新Spring[最核心]的知识点:AOP和IOC 无论是入门还是面试,理解AOP和IOC都是非常重要的.在面试的时候,我没 ...

最新文章

  1. Oralce 数据库 - 查询数据库所有的表和视图实例演示,查询指定用户下所有表和视图方法
  2. Apache Flink 零基础入门(十四)Flink 分布式缓存
  3. DataTabel中关于ImpotRow的一点尝试
  4. 计算长方体体积编程_如何求N个球体在空间中所占的体积?
  5. wampserver下配置虚拟主机 实现多站点支持
  6. 机器学习笔记(二)---- 线性回归
  7. rails 调用php函数_潜藏在PHP安全的边缘——浅谈PHP反序列化漏洞
  8. Android远程桌面助手之功能简介
  9. 我是小白0基础,现在我想学习前端开发,该如何系统的学习?
  10. 当音乐博士开始写代码...
  11. c语言实验报告约瑟夫环,C语言约瑟夫环的实现
  12. UE4 Websocket
  13. 在线文本比较工具(用来对比两个代码文件差异的地方)
  14. python10的负n次方_python中n次方怎么表示
  15. 论文阅读报告:Taxonomy-aware feature engineering for microbiome classification,Mai Oudah and Andreas Hen
  16. STC15内部ADC测电压
  17. OpenSSL 使用openssl工具搭建私有CA
  18. Python风险价值计算投资组合VaR、期望损失ES
  19. unity3d和建模关系
  20. java 拷贝图片拒绝访问_急!!!!文件夹里的图片打不开,也复制不了 现实拒绝访问,被写保护,怎么打开啊,很重大...

热门文章

  1. java程序设置软件界面(jFrame)的最小大小
  2. 配置NTP网络时间服务
  3. SQLServer数据库原理读书笔记(三)--表的物理存储
  4. Web2.0网站性能调优实践(引用王宗义)
  5. 利用Kubernetes名称空间来管理内存和CPU资源(三)
  6. leetcode76. 最小覆盖子串
  7. mysql语言的特点不包括_SQL语言具有两种使用方式,分别称为交互式SQL和__________...
  8. 网络通讯原理简介以及演示通讯过程
  9. 基于shiro实现session持久化和分布式共享
  10. Java 实现 微信支付完成回调解密返回字符串内容