MyBatis參數處理

  • 單個參數:mybatis不會做特殊處理

    #{參數名/任意名}:取出參數值。
    
  • 多個參數:mybatis會做特殊處理。

    多個參數會被封裝成 一個map,
    1. key:param1...paramN,或者參數的索引也可以。
    
    2. value:傳入的參數值
        #{}就是從map中獲取指定的key的值;
    

    若多個參數直接使用bean屬性名

    方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
    取值:#{id},#{lastName}
    

    則拋出異常:

    org.apache.ibatis.binding.BindingException: 
    Parameter 'id' not found. 
    Available parameters are [1, 0, param1, param2]
    

多個參數取值的方法

  1. 命名參數 :

    在接口定義的方法中明確指定封裝參數時map的key
    如:getEmployee(@Param("id")Integer id, @Param("lastName")String lastName)
    多個參數會被封裝成 一個map,
        key:使用@Param註解指定的值
        value:參數值
    #{指定的key}取出對應的參數值
    
  2. POJO:

    如果多個參數正好是我們業務邏輯的數據模型,我們就可以直接傳入pojo
    (將零散屬性直接封裝bean,這樣相當於傳一個參數);
    #{屬性名}:取出傳入的pojo的屬性值
    
  3. Map:

    如果多個參數不是業務模型中的數據,沒有對應的pojo,
    不經常使用,爲了方便,我們也可以傳入map
    
    如:map.put("id", employee.getId());
        map.put("lastName", employee.getLastName());
    #{id}, #{lastName}:取出map中對應的值
    
  4. To:

    如果多個參數不是業務模型中的數據,但是經常要使用,
    推薦來編寫一個TO(Transfer Object)數據傳輸對象

    Page{
        int index;
        int size;
    }
    

思考

public Employee getEmp(@Param("id")Integer id,String lastName);
取值:id==>#{id/param1}   lastName==>#{param2}

public Employee getEmp(Integer id,@Param("e")Employee emp);
取值:id==>#{param1}    lastName===>#{param2.lastName/e.lastName}

特別注意:

如果是Collection(List、Set)也會特殊處理。
也是把傳入的list或者數組封裝在map中。

key:(collection),
如果是List還可以使用這個key(list)
數組(array)
public Employee getEmpById(List<Integer> ids);
取值:取出第一個id的值:   #{list[0]}

結合源碼,mybatis如何處理參數

確定流程:
1.獲取每個標了param註解的參數的@Param的值:id,lastName;  賦值給name;
2.每次解析一個參數給map中保存信息:(key:參數索引,value:name的值)
name用來保存參數的名字,分爲使用註解和不使用兩種情況
name的值:
    標註了param註解:註解的值
    沒有標註:
        1.全局配置:useActualParamName(jdk1.8):name=參數名
        2.name=map.size();相當於當前元素的索引
            {0=id, 1=lastName,2=2}

Mybatis獲取參數的方法如下

/*getEmployee(@Param("id")Integer id, @Param("lastName")String lastName, String email)
args【1,"Tom",'hello'】 */

public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    //1、參數爲null直接返回
    if (args == null || paramCount == 0) {
      return null;

    //2、如果只有一個元素,並且沒有Param註解;args[0]:單個參數直接返回
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];

    //3、多個元素或者有Param標註
    } else {
      final Map<String, Object> param = new ParamMap<Object>();
      int i = 0;

      //4、遍歷names集合;{0=id, 1=lastName,2=2}
      for (Map.Entry<Integer, String> entry : names.entrySet()) {

        //names集合的value作爲key;  names集合的key又作爲取值的參考args[0]:args【1,"Tom"】:
        //eg:{id=args[0]:1,lastName=args[1]:Tom,2=args[2]}
        param.put(entry.getValue(), args[entry.getKey()]);


        // add generic param names (param1, param2, ...)param
        //額外的將每一個參數也保存到map中,使用新的key:param1...paramN
        //效果:有Param註解可以#{指定的key},或者#{param1}
        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;
    }
  }
}

參數值的獲取

#{}:可以獲取map中的值或者pojo對象屬性的值;
${}:也可以獲取map中的值或者pojo對象屬性的值;

select * from tbl_employee where id=${id} and last_name=#{lastName}
控制檯: select * from tbl_employee where id=2 and last_name=?

由此可見區別如下

#{}:是以預編譯的形式,將參數設置到sql語句中;
    PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去參數的值都應該去使用#{};

什麼情況下用到${}?
    原生jdbc不支持佔位符的地方我們就可以使用${}進行取值
    比如分表、排序。。。;按照年份分表拆分
    select * from ${year}_salary where xxx;
    select * from tbl_employee order by ${f_name} ${order}    

#{}更豐富的用法

規定參數的一些規則:
javaType、 jdbcType、 mode(存儲過程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未來準備支持的功能);

jdbcType通常需要在某種特定的條件下被設置:
在我們數據爲null的時候,有些數據庫可能不能識別mybatis對null的默認處理。
比如Oracle(報錯);

JdbcType OTHER:無效的類型;
因爲mybatis對所有的null都映射的是原生Jdbc的OTHER類型,
oracle不能正確處理;

由於全局配置中:jdbcTypeForNull=OTHER;oracle不支持;兩種辦法
1、#{email,jdbcType=NULL};
2、jdbcTypeForNull=NULL
<setting name="jdbcTypeForNull" value="NULL"/>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章