• Mybatis第三篇:参数解析


      Mybatis的参数传递情况分为:一个参数、Map参数、javaBean参数、多个参数、Collection参数、List参数、Array数组参数。

    一、一个参数

      Dao层的接口方法中传入的参数只有一个,XML文件中的取值变量可以任意写(#{value}可以写任意值)。

    <select id="getUserByName" parameterType="string" resultMap="BaseResultMap">
      select * from t_user where `name` = #{value}
    </select>

     二、传入Map对象

      多个参数时,传递Map对象,以key作为参数名称,value作为参数值。

      1、map参数拼接

    Map<String, Object> map = new HashMap<>();
    map.put("id", 2L);
    map.put("name", "啦啦啦");
    List<TUser> users = userDao.getUserByMap(map);

      2、sql获取参数

    <select id="getUserByMap" parameterType="map" resultMap="BaseResultMap">
        select * from t_user where `id` = #{id} OR `name` = #{name}
    </select>

     三、传入javaBean对象

      参数传递依靠javaBean的字段属性来区分。取值与Map集合相似,传参受到javaBean的字段类型类型限制。

      1、javaBean对象创建

    UserDto dto = UserDto.builder().id(1L).name("啦啦啦").build();
    List<TUser> users = userDao.getUserByDtoBean(dto);

      2、sql参数获取

    <select id="getUserByDtoBean" parameterType="entity.UserDto" resultMap="BaseResultMap">
        select * from t_user where `id` = #{id} OR `name` = #{name}
    </select>

     四、多个参数传参

      dao层方法需要多个参数时,若是没有使用mybatis的@Param注解,直接调用方法,Mybatis解析XML文件时会将参数名称解析为arg1, arg0..., param1, param2....

    这样的参数名,sql的xml文件使用与dao层方法一样的名称是无法解析的。需要在dao层方法上增加@Param注解,指定解析时应该映射成的参数名。

      1、dao层接口方法,未加@Param注解

    List<TUser> getUserByParams(Long id, String name);

      2、sal参数获取

    <select id="getUserByParams" resultMap="BaseResultMap">
        select * from t_user where `id` = #{id} OR `name` = #{name}
    </select>

      3、执行结果报错

    ### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]
    ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

      4、调整dao层的接口方法,增加注解@Param

    List<TUser> getUserByParams(@Param("id") Long id, @Param("name") String name);

    五、传递List集合

      dao层接口中若是没有使用@Param注解,XML文件的sql直接使用list进行判断,若是使用了@Param注解对参数进行命名,要严格按照@Param注解的命名来。

      1、dao层方法

    List<TUser> getUserByList( List idlist);

      2、参数拼接

    List<Long> ids = Arrays.asList(1L, 2L);
    List<TUser> users = userDao.getUserByList(ids);

      3、sql参数获取

    <select id="getUserByList" parameterType="list" resultMap="BaseResultMap">
        select * from t_user where
        <if test="list != null and list.size() > 0">
          `id` IN
          <foreach collection="list" index="index" close=")" open="(" item="id" separator=",">
            #{id}
          </foreach>
        </if>

    六、参数解析的相关源码

      Debug启动测试方法,在dao层接口方法上打上断点,step into跟进方法,可以发现参数解析的源码在org.apache.ibatis.reflection.ParamNameResolver的构造方法ParamNameResolver上,这里会根据@Param注解(有@Param注解时优先使用注解的值作为参数名称),没有的话会解析为arg0、arg1....的参数名称列表。

    public ParamNameResolver(Configuration config, Method method) {
    Class<?>[] paramTypes = method.getParameterTypes();
    Annotation[][] paramAnnotations = method.getParameterAnnotations();
    SortedMap<Integer, String> map = new TreeMap();
    int paramCount = paramAnnotations.length;

    for(int paramIndex = 0; paramIndex < paramCount; ++paramIndex) {
    if (!isSpecialParameter(paramTypes[paramIndex])) {
    String name = null;
    Annotation[] var9 = paramAnnotations[paramIndex];
    int var10 = var9.length;

    for(int var11 = 0; var11 < var10; ++var11) {
    Annotation annotation = var9[var11];
    if (annotation instanceof Param) {
    this.hasParamAnnotation = true;
    name = ((Param)annotation).value();
    break;
    }
    }

    if (name == null) {
    if (config.isUseActualParamName()) {
    name = this.getActualParamName(method, paramIndex);
    }

    if (name == null) {
    name = String.valueOf(map.size());
    }
    }

    map.put(paramIndex, name);
    }
    }

    this.names = Collections.unmodifiableSortedMap(map);
    }

      初步解析成arg0、arg1....参数名列表后,后续在执行MapperMethod的executeForMany、executeForCursor等方法的时候会通过如下的这行代码对参数名做进一步的转换,具体还是调用了org.apache.ibatis.reflection.ParamNameResolver的getNamedParams(args)方法。

    Object param = method.convertArgsToSqlCommandParam(args);
    public Object getNamedParams(Object[] args) {
        final int paramCount = names.size();
        if (args == null || paramCount == 0) {
          return null;
        } else if (!hasParamAnnotation && paramCount == 1) {
          return args[names.firstKey()];
        } else {
          final Map<String, Object> param = new ParamMap<Object>();
          int i = 0;
          for (Map.Entry<Integer, String> entry : names.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey()]);
            // add generic param names (param1, param2, ...)
            final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
            // ensure not to overwrite parameter named with @Param
            if (!names.containsValue(genericParamName)) {
              param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
          }
          return param;
        }
      }

      getNamedParams方法会对传入的arg[]参数数组进行处理,符合条件的会会拼接上param1、param2...这样的参数名。不符合的按传入的arg参数返回。

  • 相关阅读:
    Jni如何传递并且修改两个基础参数
    【转】对于JNI方法名,数据类型和方法签名的一些认识
    Android应用程序开机开机启动
    Android程序中Acticity间传递数据
    2014-7-6 学期总结
    程序员的美:极致与疯狂
    《重构:改善既有代码的设计》——关于代码注释的唠叨
    2014-5-5 近期小结和计划
    Android:RelativeLayout 内容居中
    图像处理:图像灰度化
  • 原文地址:https://www.cnblogs.com/8593l/p/12680571.html
Copyright © 2020-2023  润新知