1. 程式人生 > >mybatis對映檔案引數處理

mybatis對映檔案引數處理

   單個引數:mybatis不會做特殊處理,
#{引數名/任意名}:取出引數值。儘管我們在介面中指定啦引數為ID,但在對映檔案中可以任意名,如兩端程式碼的id和anyID,測試結果如下

public Employee getEmpById(Integer id);
<select id="getEmpById"
        resultType="com.mfg.mybatis.bean.Employee" databaseId="mysql">
        select *from employee where id = #{anyID}
    </select
>

測試程式碼和結果如下:

@Test
    public void test01() throws IOException {
        // 1、獲取sqlSessionFactory物件
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        // 2、獲取sqlSession物件
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            // 3、獲取介面的實現類物件
//會為介面自動的建立一個代理物件,代理物件去執行增刪改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(3); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } }

這裡寫圖片描述

多個引數:mybatis會做特殊處理。
   多個引數會被封裝成 一個map,形成如key:param1…paramN,或者引數的索引也可以
   value:傳入的引數值
   #{}就是從map中獲取指定的key的值;
如果依然按照單個引數的取法會出現異常:
   org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found. Available parameters are [1, 0, param1, param2]
錯誤操作:

public Employee getEmpByIdAndLastName(Integer id,String lastName);
<select id="getEmpByMap"
        resultType="com.mfg.mybatis.bean.Employee">
        select * from ${tableName} where id=${id} and
        last_name=#{lastName}
    </select>
/**
     * 測試mapper引數
     * @throws IOException
     */
    @Test
    public void Test04() throws IOException {
        SqlSessionFactory sessionFactory=getSqlSessionFactory();
        SqlSession sqlSession=sessionFactory.openSession();
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmpByIdAndLastName(3,"jerry");
            System.out.println(employee);
        }finally {
            sqlSession.close();
        }
    }

報錯如下:找不到引數id 應該為1,0,param1…這種形式。
這裡寫圖片描述

此時我們有兩種修改方式
    1️⃣:修改對映檔案為引數改為param1,param2

<select id="getEmpByIdAndLastName"
        resultType="com.mfg.mybatis.bean.Employee">
        select * from employee where id = #{param1} and
        last_name=#{param2}
    </select>

但這種方式在引數多的時候,每個引數都有一個數字對應,此時推薦使用命名引數的形式
    2️⃣:命名引數形式,明確指定封裝引數時map.key;此時多個引數會被封裝成一個map,其中就key就是我們自己命名的引數名
    key:id,lastName
    key:引數值
    取值:#{我們自己的命名引數}

    public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
<select id="getEmpByMap"
        resultType="com.mfg.mybatis.bean.Employee">
        select * from ${tableName} where id=${id} and
        last_name=#{lastName}
    </select>

兩種測試都可以
這裡寫圖片描述
POJO:如果多個引數正好是我們業務邏輯的資料模型,我們就可以直接傳pojo;
#{屬性名}:取出傳入的pojo的屬性值

public void addEmp(Employee employee);

public void updata (Employee employee);

Map:如果多個引數不是業務模型中的資料,沒有對應的pojo,不經常使用,為了方便,我們也可以傳入map
#{key}:取出map中對應的值

public Employee getEmpByMap(Map<String, Object> map);
<select id="getEmpByMap"
        resultType="com.mfg.mybatis.bean.Employee">
        select * from employee where id=${id} and
        last_name=#{lastName}
    </select>
/**
     * 測試mapper引數(Map)
     * @throws IOException
     */
    @Test
    public void Test05() throws IOException {
        SqlSessionFactory sessionFactory=getSqlSessionFactory();
        SqlSession sqlSession=sessionFactory.openSession();
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Map<String, Object> map=new HashMap<String, Object>();
            map.put("id", 3);
            map.put("lastName", "Meng_FanGuang");
            Employee employee = mapper.getEmpByMap(map);
            System.out.println(employee);
        }finally {
            sqlSession.close();
        }
    }

這裡寫圖片描述
TO:如果多個引數不是業務模型中的資料,但是經常要使用,推薦來編寫一個TO(Transfer Object)資料傳輸物件
   Page{
int index;
int size;
}

   特別注意:當傳入的是物件或者map以及和基本型別或者String混合的情況時,比如:

public Employee getEmp(Integer id,@Param("e")Employee emp);
id-->{param1}  lastName-->#{param2.lastName}或者#{e.lastName}

Connection:當傳入的是集合時,比如有LIst,Set或者陣列。 也會特殊處理。也是把傳入的list或者陣列封裝在map中。key:Collection(index),如果是List還可以使用這個list ,陣列可以使用array

public Employee getEmpById(List<Integer> ids);

取值:取出第一個id的值: #{list[0]}

myBatis引數原始碼分析

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 id="getEmpByIdAndLastName"
        resultType="com.mfg.mybatis.bean.Employee">
        select * from employee where id = ${id} and
        last_name=#{lastName}
    </select>

這裡寫圖片描述
   區別
#{}:是以預編譯的形式,將引數設定到sql語句中;PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去引數的值都應該去使用#{};
   原生sql不支援佔位符的地方,我們就要使用後者來進行取值。比如分表;按照年份分表,或者排序

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不能正確處理;mybatis與JDBC原生型別的轉換如下:
這裡寫圖片描述
由於全域性配置中:jdbcTypeForNull=OTHER;oracle不支援;兩種辦法
①:通過#{}傳引數時,將null型別設定為jdbcType的other型別

#{email,jdbcType=OTHER};

②、在總配置檔案中加入下面設定

<setting name="jdbcTypeForNull" value="NULL"/>