【mybatis源碼學習】mybatis的參數處理

1、mybatis的參數處理以及參數取值

一、單個參數

  • mybatis不作任何處理算法

  • 取值方式:spring

    ​ #{參數名/任意名}sql

<!-- Employee getEmpById(Integer id);  -->
<select id="getEmpById" resultType="com.mxc.bean.Employee">
    select * from employee where id=#{id}
</select>
View Code

二、多個參數

  • mybatis會將多個參數自動封裝爲一個mapapache

    ​ key:param1,…,paramN,也能夠是0,…,N-1(即參數索引,N是參數的個數)安全

    ​ value:參數值數據結構

  • 取值方式:mybatis

    ​ #{上述的key}app

<!-- Employee getEmpByIdAndLastName(Integer id, String lastName);  -->
<select id="getEmpByIdAndLastName" resultType="com.mxc.bean.Employee">
    select * from employee where id=#{param1} and last_name=#{param2}
</select>
View Code

 

爲多個參數指定明確的key數據結構和算法

  • @Param註解能夠爲參數指定一個明確的key,方便在sql中取參數值ide

  • 取值方式:

    ​ #{@Param註解指定的key}

<!-- Employee getEmpByIdAndLastName(@Param("id")Integer id, @Param("lastName")String lastName);  -->
<select id="getEmpByIdAndLastName" resultType="com.mxc.bean.Employee">
    select * from employee where id=#{id} and last_name=#{lastName}
</select>
View Code

參數多時會封裝map,爲了取參數值方便,使用@Param來指定封裝時使用的key

 

三、參數是一個POJO

  • 若多個參數恰好是一個POJO中的屬性值,能夠直接傳入一個POJO

  • 取值方式:

    ​ #{屬性名}

<!-- Employee getEmpByIdAndLastName(Employee emp);  -->
<select id="getEmpByIdAndLastName" resultType="com.mxc.bean.Employee">
    select * from employee where id=#{id} and last_name=#{lastName}
</select>
View Code

 

四、參數是一個Map

  • 若多個參數不是某一個POJO的屬性,能夠封裝爲一個Map

  • 取值方式:

    ​ #{Map的key}

<!-- 
    Employee getEmpByIdAndLastName(Map<String, Object> map); 
    map:
        Map<String, Object> map = new HashMap<>();
        map.put("id", 1);
        map.put("lastName", "mxc");
-->
<select id="getEmpByIdAndLastName" resultType="com.mxc.bean.Employee">
    select * from employee where id=#{id} and last_name=#{lastName}
</select>
View Code

小試牛刀

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

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

 

#{}與${}的異同
同:

​ 能夠獲取map中的值或者pojo對象屬性的值

異:

#{}:是以預編譯的形式,將參數設置到sql語句中,能夠防止sql注入
${}:取出的值直接拼裝在sql語句中,會有安全問題
使用場景

大多狀況下,取參數的值使用#{}。在原生JDBC不支持佔位符的地方能夠使用${}。如按年份分表查詢:select * from ${year}_salary;

2、mybatis的參數處理的源碼實現

一、 內部數據結構

package com.spring.test.service.mybatis;

import org.apache.ibatis.builder.ParameterExpression;

/**
 * 
 */
public class paramHandler {

    public static void main(String[] args) {
        paramsTokenHandler();
    }


    /**
     * 方法名:List<User> queryList(String name, RowBounds rowBounds, int age, @Param("address") String addresss);
     * 參數內部映射:
     * MethodSignature.SortedMap<Integer, String> params
     *      參數列表的下標->參數名字(若是是@Param,則顯示的是註解的value,不然爲參數列表當前的除了RowBounds,ResultHandler之外的參數排名次數)
     *      0->0
     *      2->1
     *      3->address
     *
     * MethodSignature.convertArgsToSqlCommandParam(Object[] args)  返回:ParamMap
     *
     *     ParamMap內部存儲以下:
     *     參數名字->參數下標
     *     0->name的值
     *     1->age的值
     *     address->addresss的值
     *
     *     param1->name的值
     *     param2->age的值
     *     param3->addresss的值
     *
     */
    public static void paramsToParamMap(){

    }

    /**
     * 例子:#{checkedTime,jdbcType=BIGINT,typeHandler=com.meituan.payment.fundsgateway.core.model.handler.DateForLongTypeHandler}
     */
    public static void paramsTokenHandler(){
        String token="checkedTime,jdbcType=BIGINT,typeHandler=com.meituan.payment.fundsgateway.core.model.handler.DateForLongTypeHandler";
        ParameterExpression parameterExpression=new ParameterExpression(token);
        String name=parameterExpression.get("property");
        System.out.println(name);
        String jdbcType=parameterExpression.get("jdbcType");
        System.out.println(jdbcType);
        String typeHandler=parameterExpression.get("typeHandler");
        System.out.println(typeHandler);
    }
}
View Code

二、涉及到的特殊數據結構和算法

org.apache.ibatis.scripting.defaults.DefaultParameterHandler

=>經過sql解析的ParameterMapping循環遍歷,從參數列表中獲取指定的值,設置至sql語句中的?佔位符。

 

org.apache.ibatis.reflection.MetaObject

=>將方法的參數列表包裝成MetaObject,提供統一獲取參數值的方法

 

org.apache.ibatis.reflection.property.PropertyTokenizer

=>根據sql語句佔位符#{propertyName}中的propertyName去MetaObject中獲取sql語句中的?的值。

 

org.apache.ibatis.builder.SqlSourceBuilder

org.apache.ibatis.builder.ParameterMappingTokenHandler

org.apache.ibatis.parsing.GenericTokenParser

org.apache.ibatis.builder.ParameterExpression

=>將sql語句中#{}替換成?,並解析出List<ParameterMapping>

相關文章
相關標籤/搜索