(五)Mybatis从入门到入土——Mapper接口传参多种方式解析
这是mybatis系列第5篇。
说到底Mybatis常见的传参形式无非是传递一个参数、Map、Java对象,亦或是多个参数。下面就分别对这些进行讲解和说明。
传递一个参数
传递一个参数相对来说较为简单
用法
Mapper接口方法中只有一个参数,如:
UserModel getByName(String name);
Mapper xml引用这个name参数:
#{任意合法名称}
如:#{name}、#{val}、${x}等等写法都可以引用上面name参数的值。
直接使用即可相当的方便和简单
传递一个Map参数
用法
如果我们需要传递的参数比较多,参数个数是动态的,那么我们可以将这些参数放在一个map中,key为参数名称,value为参数的值。在工作中,这种可以说是最常见的。大多数情况下都可以进行使用
Mapper接口中可以这么定义,如:
List<UserModel> getByMap(Map<String,Object> map);
如我们传递:
Map<String, Object> map = new HashMap<>(); map.put("id", 1L); map.put("name", "冢狐");
对应的mapper xml中可以通过#{map中的key}可以获取key在map中对应的value的值作为参数,如:
SELECT * FROM t_user WHERE id=#{id} OR name = #{name}
传递一个java对象参数
当参数比较多,但是具体有多少个参数我们是确定的时候,我们可以将这些参数放在一个javabean对象中。这样也有利于理解,知道需要传递那些参数,不想map一样对于传递的参数不是很明确。
如我们想通过userId和userName查询,可以定义一个dto对象,属性添加对应的get、set方法,如:
@Getter @Setter @ToString @Builder @NoArgsConstructor @AllArgsConstructor public class UserFindDto { private Long userId; private String userName; }
传递java对象的方式相对于map的方式更清晰一些,可以明确知道具体有哪些参数,而传递map,我们是不知道这个map中具体需要哪些参数的,map对参数也没有约束,参数可以随意传,建议多个参数的情况下选择通过java对象进行传参。
传递多个参数
上面我们介绍的都是传递一个参数,那么是否可以传递多个参数呢?我们来试试吧。
多参数mybatis的处理
mybatis处理多个参数的时候,会将多个参数封装到一个map中,map的key为参数的名称,java可以通过反射获取方法参数的名称,下面这个方法:
UserModel getByIdOrName(Long id, String name);
编译之后,方法参数的名称通过反射获取的并不是id、name,而是arg0、arg1,也就是说编译之后,方法真实的参数名称会丢失,会变成arg+参数下标的格式。
所以上面传递的参数相当于传递了下面这样的一个map:
Map<String,Object> map = new HashMap<>(); map.put("arg0",id); map.put("arg1",name);
所以说我们的方法真实的参数名称会丢失,如果要想使用真实的参数名称,就需要在编译java代码使用javac命令的时候带上-parameters参数,当编译代码的时候加上这个参数,方法的实际名称会被编译到class字节码文件中,当通过反射获取方法名称的时候就不是arg0、arg1这种格式了,而是真实的参数名称:id、name了。
我们来修改一下maven的配置让maven编译代码的时候加上这个参数,修改pom.xml中的build元素,这个元素中加入下面代码:
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins>
idea中编译代码也加一下这个参数,操作如下:
点击File->Settings->Build,Execution,Deployment->Java Compiler,如下图:
下面我们将xml中的getByIdOrName对应的sql修改成下面这样:
SELECT * FROM t_user WHERE id=#{arg0} OR name = #{arg1} LIMIT 1
使用maven命令重新编译一下chat01的代码,cmd命令中mybatis-demo/pom.xml所在目录执行下面命令:
mvn clean compile -pl :chat01
参数名称变成了真实的名称了,但是还是有param1、param2,方法参数名称不管怎么变,编译方式如何变化,param1, param2始终在这里,这个param1, param2就是为了应对不同的编译方式导致参数名称而发生变化的,mybatis内部除了将参数按照名称->值的方式放入map外,还会按照参数的顺序放入一些值,这些值的key就是param+参数位置,这个位置从1开始的,所以id是第一个参数,对应的key是param1,name对应的key是param2,value对应的还是参数的值,所以mybatis对于参数的处理相当于下面过程:
Map<String,Object> map = new HashMap<>(); map.put("反射获取的参数id的名称",id); map.put("反射获取的参数name的名称",name); map.put("param1",id); map.put("param2",name);
使用注意
使用参数名称的方式对编译环境有很强的依赖性,如果编译中加上了
-parameters
参数,参数实际名称可以直接使用,如果没有加,参数名称就变成arg下标
的格式了,这种很容易出错sql中使用
param1、param2、paramN
这种方式来引用多参数,对参数的顺序依赖性特别强,如果有人把参数的顺序调整了或者调整了参数的个数,后果就是灾难性的,所以这种方式不建议大家使用。
多参数中用@param指定参数名称
刚才上面讲了多参数传递的使用上面,对参数名称和顺序有很强的依赖性,容易导致一些严重的错误。
mybatis也为我们考虑到了这种情况,可以让我们自己去指定参数的名称,通过@param(“参数名称”)来给参数指定名称。
/** * 通过id或者name查询 * * @param id * @param name * @return */ UserModel getByIdOrName(@Param("userId") Long id, @Param("userName") String name);
上面我们通过@Param注解给两个参数明确指定了名称,分别是userId、userName,对应的user.xml中也做一下调整,如下:
<!-- 通过id或者name查询 --> <select id="getByIdOrName" resultType="zhonghu.mybatis.chat01.UserModel"> <![CDATA[ SELECT * FROM user WHERE id=#{userId} OR name = #{userName} LIMIT 1 ]]> </select>
ResultHandler作为参数
用法
查询的数量比较大的时候,返回一个List集合占用的内存还是比较多的,比如我们想导出很多数据,实际上如果我们通过jdbc的方式,遍历ResultSet的next方法,一条条处理,而不用将其存到List集合中再取处理。
mybatis中也支持我们这么做,可以使用ResultHandler对象,犹如其名,这个接口是用来处理结果的,先看一下其定义:
public interface ResultHandler<T> { void handleResult(ResultContext<? extends T> resultContext); }
里面有1个方法,方法的参数是ResultContext类型的,这个也是一个接口,看一下源码:
public interface ResultContext<T> { T getResultObject(); int getResultCount(); boolean isStopped(); void stop(); }
4个方法:
getResultObject:获取当前行的结果
getResultCount:获取当前结果到第几行了
isStopped:判断是否需要停止遍历结果集
stop:停止遍历结果集
ResultContext接口有一个实现类org.apache.ibatis.executor.result.DefaultResultContext,mybatis中默认会使用这个类。
最后
如果觉得看完有收获,希望能关注一下,顺便给我点个赞,这将会是我更新的最大动力,感谢各位的支持