MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式。
单个参数:实体类、Map集合、Collection、List、Array以及其他类型。
多个参数:Param注解定义的名称要与sql语句中参数占位符中的名称相同。
这里就引入了一个问题:为什么需要Param注解,以及使用Param注解时参数是如何进行传递的?那么就需要对MyBatis底层对于这些参数进行不同的封装处理方式进行深刻的理解。
MyBatis提供了ParamNameResolver类来进行参数封装参数封装,下面进入源码进行分析:
1.首先先看一下多个参数是如何进行传递的:
先准备一个UserMapper类的查询方法:
UserInfo select(@Param("username") String username, @Param("password") String password);
准备一个UserMapper.xml中的sql:
<select id="select" resultType="model.UserInfo">
select * from tb_user where username=#{username} and password = #{password}
</select>
关于多个参数的传递,其实是封装为Map集合的:
map.put(“arg0”,参数值1);
map.put(“param1”,参数值1);
map.put(“arg1”,参数值2);
map.put(“param2”,参数值2);
其实也就是说在sql中我们可以通过arg0、arg1、param1、param2等来获取对应的参数。
首先,不加param注解的时候,这个时候运行会报错,但是我们可以看到一些提示信息:
意思就是说,当前传递的参数没有获取到,目前能够获取的参数有[arg1, arg0, param1, param2]这四个。接下来把sql中占位符的参数改成arg0和arg1,此时运行成功。同理,占位符的参数改成param1和param2,也是能够运行成功的。
接下来,我们看一下ParamNameResolver类的源码,里面有一个getNamedParams方法:通过断点调试的方法我们能够清晰看到整个过程:(这里具体过程不赘述,只看结果)
分析结果就是,咱们其实是可以用arg0、arg1、param1、param2等来获取对应的参数,但是不推荐,因为当多个参数进行传递时,使用这种方式会让代码可读性非常差。推荐使用@Param注解来定义参数名称。使用@Param注解其实就是替换了map集合中的arg的键名,param的键名是不变的,下面代码演示能够说明问题。
2.现在看一下单个参数是如何进行传递的:
1.实体类
可以直接使用,属性名和参数占位符保持一致就可以。
2.Map集合
可以直接使用,键名和参数占位符保持一致就可以。
3.其他类型
可以直接使用。比如int id,sql中占位符写什么都是可以的。示例:
4.Collection(list/array)
准备传入一个集合参数:
通过断点调试还是会进入getNamedParams方法,然后进入wrapToMapIfCollection方法:
小结:
传入的collection集合,那么会封装为Map集合:
map.put(“arg0”,collection集合);
map.put(“collection”,collection集合);
传入的list集合,那么也会封装为Map集合:
map.put(“arg0”,list集合);
map.put(“collection”,list集合);
map.put(“list”,list集合);
传入的array数组,那么也会封装为Map集合:
map.put(“arg0”,array数组);
map.put(“array”,array数组);
3.总结
在实际开发中当传入多个参数、collection集合、list集合和array数组等的时候,要尽量避免使用这种默认的参数,最好使用@Param注解来替换Map集合中的默认键名,并使用修改后的名称来获取值,这样会使代码可读性更高。