mybatis源码学习mybatis的参数处理

Posted shangxiaofei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis源码学习mybatis的参数处理相关的知识,希望对你有一定的参考价值。

一、mybatis的参数处理以及参数取值

1、单个参数

  • mybatis不做任何处理

  • 取值方式:

    ? #参数名/任意名

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

2、多个参数

  • mybatis会将多个参数自动封装为一个map

    ? key:param1,…,paramN,也可以是0,…,N-1(即参数索引,N是参数的个数)

    ? value:参数值

  • 取值方式:

    ? #上述的key

技术图片
<!-- 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中取参数值

  • 取值方式:

    ? #@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

 

3、参数是一个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

 

4、参数是一个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;

二、mybatis的参数处理的源码实现

1、 内部数据结构

技术图片
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

2、涉及到的特殊数据结构和算法

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>

以上是关于mybatis源码学习mybatis的参数处理的主要内容,如果未能解决你的问题,请参考以下文章

mybatis框架源码学习

Mybatis 源码学习-反射工具(TypeParameterResolver)

MyBatis核心源码深度剖析工作机制和实现原理

Mybatis 实现批量插入和批量删除源码实例

mybatis源码阅读-helloword

重新学习Mybatis