MyBatis(四):参数处理器

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

下面就来看看参数处理器

回顾

下面就来看看这个过程如何,之前去执行Executor执行doQuery方法时,在生成prepareStatement时,会调用parameterize方法去匹配参数,里面就会调用参数处理器ParameterHandler去处理,那我们就从那里开始看起
在这里插入图片描述
这里由于执行的是预编译也就是prepareStatementHandler,至于为什么会是这个,回看上一篇MyBatis(二):StatementHandler

这里简单说一下,经过 RoutingStatementHandler简单工厂模式在装饰PrepareStatementHandler的
在这里插入图片描述
PrepareStatementHandler直接调用了parameterHandler

参数处理器(ParameterHandler)

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

有两种情况

  • 一个参数,默认不作任何的处理,除非设置了@param注解,会用唯一的参数与占位符进行对应(占位符随便写什么都行)
  • 多个参数(转化成Map,基于key进行映射)
    • 通过顺序方式,转化成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);
          }
        }
      }
    }
  }

从代码上可以看到

参数处理器有主要几个对象

  • parameterMappings:为一个ArrayList,里面是多个parameterMapping,一个parameterMapping代表SQL语句中的参数,并标明MODE、javaType和typeHandler等属性,也就是相当于sqk参数的处理形式都在里面
    在这里插入图片描述

  • parameterObject:表明SQL参数与实际传进来的参数的映射关系!,可以看到里面有4个值,param1和param2是一定会有的,而arg0、arg1则是默认生成的,假如用了@Param注解,arg0和arg1将会变回@Param里面的值,假如只有一个参数,那么就不会进行处理,一般都会与parameterMapping的property一一对应,除了一种特殊情况(只有一个参数)

下面来看看没加@Param注解前

没加注解前
在这里插入图片描述

加了注解后
在这里插入图片描述
假如参数只有一个,那么parameter就不是一个Map了,而只是一个引用类型!
在这里插入图片描述
这也是为什么在代码上会有一个判断有没有注册parameterObject的类型处理器,如果有,value直接为parameterObject(对于引用类型肯定是有注册类型处理器的,但对于Map是没有类型处理器的!)

前面提到过,只有一种参数,那么parameterMapping和parameter是不可能对应上的(因为没必要对应)

在这里插入图片描述
在这里插入图片描述
可以看到,property甚至都没用JDK反射生成的arg0,arg1那些,直接使用了SQl写的占位符value

typeHandler去匹配参数

DefaultParameterHandler用来存储一句SQL里面的所有参数与传进来的参数的映射关系,现在映射关系找到了,下面就需要进行类型处理了,因为MySQL的数据类型与Java的数据类型是不一样的,需要进行转换,在MyBatis中负责这一块的为TypeHandler类,而每一个parameterMapping都有自己的TypeHandler

具体的方法为setParameter方法

setParameter方法

在这里插入图片描述
而对于TypeHandler是一个接口,用来做MySQL数据类型与Java数据类型转化处理的

所以,MyBatis基本对于每一个Java数据类型都有TypeHandler
在这里插入图片描述

所以这个匹配规则会根据很多类的不同而不同,有兴趣自己去看就好了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值