写点什么

MyBatis(四):参数处理器,linux 运维架构师

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:2123 字

    阅读完需:约 7 分钟

前面已经提到了,StatementHadnler 会调用参数处理器和结果集映射器来分别做 SQL 参数的匹配(JavaBean 转化成 JDBC 的参数),和 SQL 查询出来的结果集转换成 JavaBean


下面就来看看参数处理器


回顾




下面就来看看这个过程如何,之前去执行 Executor 执行 doQuery 方法时,在生成 prepareStatement 时,会调用 parameterize 方法去匹配参数,里面就会调用参数处理器 ParameterHandler 去处理,那我们就从那里开始看起



这里由于执行的是预编译也就是 prepareStatementHandler,至于为什么会是这个,回看上一篇 MyBatis(二):StatementHandler


这里简单说一下,经过 RoutingStatementHandler 简单工厂模式在装饰 PrepareStatementHandler 的



PrepareStatementHandler 直接调用了 parameterHandler


参数处理器(ParameterHandler)




所有的参数转化,都是经过 ParamNameResolver 去做的


有两种情况


  • 一个参数,默认不作任何的处理,除非设置了 @param 注解,会用唯一的参数与占位符进行对应(占位符随便写什么都行)

  • 多个参数(转化成 Map,基于 key 进行映射)

  • 通过顺序方


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


式,转化成 param1,param2…作为 key,value 为传进来的值


  • 加上 param 注解,可以自定义 key,取代生成的 arg0。。。

  • 基于反射获取变量名称,JDK1.8 才支持,如果不支持转换成 arg0、arg1。。等

  • 为一个 JavaBean 时,也会映射一个 Map 出来


参数转化的操作位于 ParamNameResolver 中的 getNamedParams 方法里


而 PrepareStatementHandler 为一个接口,而且对应的实现类只有一个 DefaultParameterHandler(所以,一定会经过 DefaultParameterHandler)



这里要注意的一点是,这里的处理并不是经过动态代理的!动态代理是在 SqlSession 前去做的(以后再讲动态代理层面上)


可以参考下面的执行情况(可以看到动态代理过程在最前面的,即只有一层动态代理)



下面还是回归看,怎么去填充参数的吧

DefaultParameterHandler

这个是唯一的 ParameterHandler 实现类,所以参数处理都是交给他去做的,处理参数的方法为 setParameter,下面是源码


@Override


public void setParameters(PreparedStatement ps) {


ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());


//此时 boundSql 封装了 sql、输入的参数、sql 参数的映射


//这里是获取 sql 参数的映射(不包括值)


List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();


//如果参数的映射不为空,也就是(一般不会为空,顶多 size 为 0)


//当 sql 里面没有参数,比如 select all 就没有这些参数的映射了


//此时 parameterMappings 就会为 size = 0


if (parameterMappings != null) {


for (int i = 0; i < parameterMappings.size(); i++) {


//获取每一个参数映射


ParameterMapping parameterMapping = parameterMappings.get(i);


//如果参数映射的类型不为 OUT


//参数映射的类型有 IN OUT INOUT 三种


//如果为 OUT 是不做处理的


if (parameterMapping.getMode() != ParameterMode.OUT) {


//这个 value 是用来存储额外的参数的,其实就是 sql 参数对应传进去的值!


Object value;


//获取映射的名称,如果没有加 param 注解且多个参数,就是 arg0,arg1。。那些


String propertyName = parameterMapping.getProperty();


//判断当前这个映射的参数有没有额外参数


if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params


value = boundSql.getAdditionalParameter(propertyName);


}


//判断 parameterObject 是否为空


//parameterObject 是用来存储映射关系的,也就是 sql 参数与传进来的参数映射


//比如 arg0~123


//也就是如果没有传进来的参数,那么额外参数 value 也为 null


else if (parameterObject == null) {


value = null;


}


//TypeHandler 为类型处理器,也就是用来转化 JavaBean 和 SQL 列数组映射的


//这里是针对只有一个参数的时候


//只有一个参数的时候,parameterObject 不是一个 Map,而是一个引用类型


//这时候就会注册相对应的处理器了(没有 Map 的处理器)


else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {


value = parameterObject;


}


//一般来说都是 else 这里进行处理


else {


//获取 parameter 的元数据


MetaObject metaObject = configuration.newMetaObject(parameterObject);


//从元数据中去获取该 sql 参数对应的值!


value = metaObject.getValue(propertyName);


}


//获取这个映射参数的类型处理器


//在 parameterMapping 中有已经固定了类型处理器


TypeHandler typeHandler = parameterMapping.getTypeHandler();


//同时去获取 jdbc 的类型


JdbcType jdbcType = parameterMapping.getJdbcType();


//如果没有设置 jdbc 连接类型且映射 Sql 参数的值为 null


//不太懂。。。


if (value == null && jdbcType == null) {


jdbcType = configuration.getJdbcTypeForNull();


}


//交由 typeHandler 去进行转化参数


//也就是由 Java 类型去转化成 sql 类型


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);


}


}


}


}


}

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
MyBatis(四):参数处理器,linux运维架构师