mybatis中@Param用法注意事项


背景:

   DAO中定义了一个方法为:List<People> getAllPeople(@Param("vo") SearchVo vo,@Param("id")String id) ;

   service层调用这个方法是:  peopleDao.getAllPeople(ViewSearchVo vo,String id) ;

   其中ViewSearchVo 是searchVo 的子类,而且 age字段是ViewSearchVo 特有的属性;   

    但是,但是,我调用传这个方法,发现age这个变量可以正常传达到sql中,让俺一下懵逼了,莫非mybatis使用了类型强制转换,(强制类型转换是有风险的,不提倡使用)


过程:

   我在网上寻找我的疑问,看是否有童鞋遇到我类似的困惑,但是转了几圈没有得到有效的信息(不知道使用什么关键字搜索)。所以就撸其mybaits的源码来看看。

   撸的这个源码是mybatis的3.3.0版本。


   Mapper文件的注册,解析主要靠MapperRegistry这个类,这个就不跳过不分析了。


  第一个关键的类,一个初始化过程中的MapperAnnotationBuilder.parse(),其中parseStatement(method)就是解析入参等信息

Method[] methods = type.getMethods();
for (Method method : methods) {
  try {
    // issue #237
    if (!method.isBridge()) {
      parseStatement(method); //解析入参信息
    }
  } catch (IncompleteElementException e) {
    configuration.addIncompleteMethod(new MethodResolver(this, method));
  }
}

  

    

void parseStatement(Method method) {
  Class<?> parameterTypeClass = getParameterType(method);  //返回入参的类型 
  LanguageDriver languageDriver = getLanguageDriver(method);
  SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);

 

private Class<?> getParameterType(Method method) {
  Class<?> parameterType = null;
  Class<?>[] parameterTypes = method.getParameterTypes();
  for (int i = 0; i < parameterTypes.length; i++) {
    if (!RowBounds.class.isAssignableFrom(parameterTypes[i]) && !ResultHandler.class.isAssignableFrom(parameterTypes[i])) {
      if (parameterType == null) {
        parameterType = parameterTypes[i];
      } else {
        // issue #135
        parameterType = ParamMap.class;  //大于1个的入参,使用map的方式返回
      }
    }
  }
  return parameterType;
}


对于只有0或者1入参,getParameterType返回的就是null或者该入参的类型,但是大于一个的入参,返回一个paramMap,而且中paramMap的类型是一个泛型,也就是说,接收的value可以是任何类型。


第二个关键的类是MapperMethod,其中对应的方法是 MapperMethod.MethodSignature.convertArgsToSqlCommandParam(Object[] args),这个方法是将运行中的dao中的入参转化为sql的入参。 


public Object convertArgsToSqlCommandParam(Object[] args) {
  final int paramCount = params.size();
  if (args == null || paramCount == 0) {
    return null;
  } else if (!hasNamedParameters && paramCount == 1) {
    return args[params.keySet().iterator().next().intValue()];
  } else {
    //使用ParamMap<Object>等价于map<String,Object>来保存多个入参
    final Map<String, Object> param = new ParamMap<Object>();
    int i = 0;
    for (Map.Entry<Integer, String> entry : params.entrySet()) {
      param.put(entry.getValue(), args[entry.getKey().intValue()]);
      // issue #71, add param names as param1, param2...but ensure backward compatibility
      final String genericParamName = "param" + String.valueOf(i + 1);
      if (!param.containsKey(genericParamName)) {
        param.put(genericParamName, args[entry.getKey()]);
      }
      i++;
    }
    return param;
  }
}

总结:paramMap由于value是Object,所以我前面提到的问题,传子类的特定属性也可以通过就可以解释清楚了,mybats的@param接收的参数根本就是object,是在运行时确定它的类型,所以使用@param可以偷懒,直接写成List<People> getAllPeople(@Param("vo") Object vo,@Param("id")Object id),也是正常工作,但是不建议这样操作,会增加代码的阅读困难



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值