MyBatis的参数处理

单个简单类型参数
  • 单个:接口中方法的参数只有一个

  • 简单类型:接口中方法的参数类型为简单类型。包括基本数据类型 + 包装类 + String + java.util.Date + java.sql.Date

  • 其实sql标签中有一个属性:parameterType。顾名思义,它用来指定参数的类型,但由于mybatis能够在获得参数后自动推断出该参数的类型,因此该属性可以省略。并且mybatis对这些类型也起了别名,比如byte的别名为_byte.

    • <select id="selectById" resultType="student" parameterType="long">
              select * from t_student where id = ${id};
          </select>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16

      * 还有map集合作为参数,pojo类作为参数。mybatis都能自动推断其类型

      *

      ##### 多参数

      * 指接口中的方法有多个参数。

      * 当有多个参数时,mybatis底层会自动创建一个map集合,以这些参数的下标值作为key,参数值作为value放入map中。比如map.put("arg0",name)或者map.put("param1",name);

      * 可以在方法中使用param注解指定key值。比如

      * ```java
      public void selectByIdAndName(@Param("id")Long id,@Param("name")String name);
      //注解中的属性值可以省略不写
底层源码分析

当我们在mybatis中进行数据库表的操作时(也就是调用接口中的方法),首先会执行以下代码

1
2
3
4
Object invoke(Object proxy,Method method,Object[] args)
//proxy:代理对象
//method:目标方法(就是接口中的方法)
//args:目标方法中的参数

mybatis底层会先判断要执行的是哪种操作:insert、update、select、delete。如果是DML语句,那么会直接执行下述代码。进行参数转换

1
param = this.method.convertArgsToSqlCommandParam(args);

如果是查询语句,那么会根据返回值类型的不同执行不同的方法。然后也会执行上述代码,进行参数转换。

底层会调用ParamNameResolver的getNamedParams方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public Object getNamedParams(Object[] args) {
//这个names是一个sortedMap集合
//private final SortedMap<Integer, String> names;
//存储了注解中给定的属性名
int paramCount = this.names.size();
if (args != null && paramCount != 0) {
//如果没有使用注解或者只有一个注解(f)
if (!this.hasParamAnnotation && paramCount == 1) {
Object value = args[(Integer)this.names.firstKey()];
return wrapToMapIfCollection(value, this.useActualParamName ? (String)this.names.get(this.names.firstKey()) : null);
} else {
//如果使用了注解,创建一个新的map集合
Map<String, Object> param = new ParamMap();
int i = 0;
//遍历names集合
for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
Entry<Integer, String> entry = (Entry)var5.next();
//假设names集合中现在存储的是(0,'name'),args=["张三"]
//param中就会存储("name","张三")
param.put((String)entry.getValue(), args[(Integer)entry.getKey()]);
String genericParamName = "param" + (i + 1);
if (!this.names.containsValue(genericParamName)) {
//这一步是生成通用属性名:("param1","张三")
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
}

return param;
}
} else {
return null;
}

总结

在Sql语句中

  • 当接口中方法的参数是单个且是基本数据类型时,可以直接使用#{}取出,且#{}内可以随意写
  • 当接口中方法的参数是单个且是pojo类或map集合时,也可以使用#{}取出,但#{}内需要写对应的属性名或key值
  • 当接口中方法的参数有多个且没有使用@Param注解时,也是使用#{}取出,但#{}内只能写arg0,arg1…或者param1,param2
  • 当接口中方法的参数有多个且使用了@Param注解时,可以使用#{}取出也可以直接用注解指定的名字取出,但#{}内可以写注解指定的属性名