(五)Mybatis从入门到入土——Mapper接口传参多种方式解析

这是mybatis系列第5篇。没看前文的建议先去【Java冢狐】公众号中查看前文,方便理解和掌握。

说到底Mybatis常见的传参形式无非是传递一个参数、Map、Java对象,亦或是多个参数。下面就分别对这些进行讲解和说明。

传递一个参数

传递一个参数相对来说较为简单

用法

Mapper接口方法中只有一个参数,如:

UserModel getByName(String name);

Mapper xml引用这个name参数:

#{任意合法名称}

如:#{name}、#{val}、${x}等等写法都可以引用上面name参数的值。image.gif直接使用即可相当的方便和简单

传递一个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,如下图:

image.gif image

下面我们将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中默认会使用这个类。

最后

  • 如果觉得看完有收获,希望能关注一下,顺便给我点个赞,这将会是我更新的最大动力,感谢各位的支持
  • 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
  • 求一键三连:点赞、转发、在看。
  • 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。

——我是冢狐,和你一样热爱编程。

欢迎关注公众号“ Java冢狐”,获取最新消息

猜你喜欢

转载自blog.csdn.net/issunmingzhi/article/details/113793746