zoukankan      html  css  js  c++  java
  • Mybatis 传递参数中的_paramter 的理解

    原因:
    以前在传递参数的时候,出现传递单个参数,有的时候用#{id} 可以成功,有的时候报错,只能改成#{_parameter}

    ---------------------------------------------------------------------------------------------------------------------------

    分析:

    参数的使用分为两部分:

    • 第一种就是常见#{username}或者${username}
    • 第二种就是在动态SQL中作为条件,例如<if test="username!=null and username !=''">

    动态SQL为什么会处理参数呢?

    主要是因为动态SQL中的<if>,<bind>,<foreache>都会用到表达式,表达式中会用到属性名,属性名对应的属性值如何获取呢?获取方式就在这关键的一步。不知道多少人遇到Could not get property xxx from xxxClass: Parameter ‘xxx’ not found. Available parameters are[…],都是不懂这里引起的。

    DynamicContext.java中,从构造方法看起:

    public DynamicContext(Configuration configuration, Object parameterObject) {
      if (parameterObject != null && !(parameterObject instanceof Map)) {
        MetaObject metaObject = configuration.newMetaObject(parameterObject);
        bindings = new ContextMap(metaObject);
      } else {
        bindings = new ContextMap(null);
      }
      bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
      bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
    }

    这里的Object parameterObject就是我们经过前面两步处理后的参数。这个参数经过前面两步处理后,到这里的时候,他只有下面三种情况:

    1. null,如果没有入参或者入参是null,到这里也是null
    2. Map类型,除了null之外,前面两步主要是封装成Map类型。
    3. 数组、集合和Map以外的Object类型,可以是基本类型或者实体类。

    看上面构造方法,如果参数是1,2情况时,执行代码bindings = new ContextMap(null);参数是3情况时执行if中的代码。我们看看ContextMap类,这是一个内部静态类,代码如下:

    static class ContextMap extends HashMap<String, Object> {
      private MetaObject parameterMetaObject;
      public ContextMap(MetaObject parameterMetaObject) {
        this.parameterMetaObject = parameterMetaObject;
      }
      public Object get(Object key) {
        String strKey = (String) key;
        if (super.containsKey(strKey)) {
          return super.get(strKey);
        }
        if (parameterMetaObject != null) {
          // issue #61 do not modify the context when reading
          return parameterMetaObject.getValue(strKey);
        }
        return null;
      }
    }

    我们先继续看DynamicContext的构造方法,在if/else之后还有两行:

    bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
    bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());

    其中两个Key分别为:

    public static final String PARAMETER_OBJECT_KEY = "_parameter";
    public static final String DATABASE_ID_KEY = "_databaseId";

    也就是说1,2两种情况的时候,参数值只存在于"_parameter"的键值中。3情况的时候,参数值存在于"_parameter"的键值中,也存在于bindings本身。

    当动态SQL取值的时候会通过OGNL从bindings中获取值。MyBatis在OGNL中注册了ContextMap:

    static {
      OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
    }

    当从ContextMap取值的时候,会执行ContextAccessor中的如下方法:

    @Override
    public Object getProperty(Map context, Object target, Object name)
        throws OgnlException {
      Map map = (Map) target;
    
      Object result = map.get(name);
      if (map.containsKey(name) || result != null) {
        return result;
      }
    
      Object parameterObject = map.get(PARAMETER_OBJECT_KEY);
      if (parameterObject instanceof Map) {
        return ((Map)parameterObject).get(name);
      }
    
      return null;
    }

    参数中的target就是ContextMap类型的,所以可以直接强转为Map类型。 
    参数中的name就是我们写在动态SQL中的属性名。

    -------------------------------------------------总结----------------------------------------------------
    1  动态SQL 中的参数和${_param}的参数,采用的都是OGNL的方式来调用参数,这时,如果是单个参数的话,只能采用_paramter的方式来传递值
      也就是只能靠

      public static final String PARAMETER_OBJECT_KEY = "_parameter";

      这个转换后的方式来传递参数

    2  #{_parame}的方式,如果是传递的单个参数,那么在#{_param}中可以随便写,可以用#{id}(方便理解)或者#{_parameter}

  • 相关阅读:
    Android JNI 本地开发接口
    Android 主题切换 小结
    Android 屏幕适配
    android 中获取视频文件的缩略图(非原创)
    android 多媒体数据库(非原创)
    Android tween 动画 XML 梳理
    activity 四种启动模式
    Activity 横竖屏切换
    Android Activity 管理 (AppManager)(非原创)
    Android moveTaskToBack(booleannon Root)
  • 原文地址:https://www.cnblogs.com/leonkobe/p/4628276.html
Copyright © 2011-2022 走看看