总结
- 多个参数:mybatis会做特殊处理。多个参数会被封装成一个map
key : param1….paramN,或者使用@Param注解指定的值
value:传入的参数值
//id获取的方式有两种 #{param1} 或者#{id}
//name获取的方式有两种 #{param2}或者 #{name}
selectUserByIdAndName(@Param("id") Integer id, @Param("name") String name);
传参的方式
- POJO:如果多个参数正好是业务逻辑的数据模型,就可以直接传入pojo;使用#{属性名}:取出传入的pojo属性值
- Map :如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,也可以传入map;#{key}:取出map中对应的值
- TO : 如果多个参数不是业务模型中的数据,但经常要使用,推荐编写一个TO(Transfer object)
//取值:id==>#{id/param1} username==>#{param2}
User selectUserByIdAndName(@Param("id") Integer id, String name);
//取值:id==>#{param1} username==>#{param2.username}
User selectUserByIdAndName(Integer id, User user);
/**
注意 如果是collection(List、Set)类型或者数组,mybatis也会做特殊处理,也是把传入的list或者数组封装在map中。key根据参数的不同,分别为collection、list、array
*/
//取值:取出第一个id的值 #{list[0]}
User selectUserByIds(List<Integer> ids);
源码分析
//names:在构造器的时候就确定好了
//selectUserByIdAndName(@Param("id") Integer id, @Param("name") String name); 返回("0","id"),("1","name")
public ParamNameResolver(Configuration config, Method method) {
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
int paramCount = paramAnnotations.length;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
//获取标注了param注解的参数@Param的值,以上述方法为例,则取到值的值为id,name
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
if (config.isUseActualParamName()) {
//使用了全局配置,useActualParamName(jdk1.8):name=参数名
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue #71
//没有param注解,没有全局配置,name=当前元素的索引
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
//使用ParamNameResolver解析参数封装为map
public Object getNamedParams(Object[] args) {
int paramCount = this.names.size();
if (args != null && paramCount != 0) {
//如果没有param注解并且参数只有一个,则直接返回单个参数
if (!this.hasParamAnnotation && paramCount == 1) {
return args[(Integer)this.names.firstKey()];
} else {
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();
//value的值可以是param的属性或者参数索引
//param中放入{"id":arg[0],"name":arg[1]}
param.put(entry.getValue(), args[(Integer)entry.getKey()]);
String genericParamName = "param" + String.valueOf(i + 1);
if (!this.names.containsValue(genericParamName)) {
/*同时param中放入{"param1":arg[0],"param2":arg[1]},最终的效果就是如果有param注解,使用#{指定的key}或者#{paramN}获取参数,没有注解,使用#{paramN}获取参数*/
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
}
return param;
}
} else {
return null;
}
}
经过参数封装后,可以获取到一个map,但是mybatis对参数又进行了一次处理
//如果是Collection,则map的key=collection,如果是List,则key=list,如果是数组,则key=array
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<>();
map.put("array", object);
return map;
}
return object;
}