# MyBatis教程 - 5 传递和获取参数
下面开始讲解在 XxxMapper.java 接口中传递参数,XxxMapper.xml 文件中获取参数。
# 5.1 获取参数值的两种方式
在通过用户名查询用户的时候,可以编写接口如下:
/**
 * 根据用户名查询用户
 */
User selectByUsername(String username);
2
3
4
在 UserMapper.xml 中通过 #{username} 获取参数,如下:
<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username}
</select>
2
3
4
除了使用 #{} 可以获取参数,还可以使用 ${} 获取参数。
<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = '${username}'
</select>
2
3
4
注意,${username} 本质是字符串拼接,所以需要加 '' ,拼接成 WHERE username = 'doubi' 这样的格式。
而 #{username} 会被替换为相应的参数值,并且根据参数的类型(例如 String、int 等)自动处理值的格式,例如是 String 类型,会自动添加 ''。
总结 #{} 和  ${} 的区别:
- #{}:本质是占位符赋值,SQL 是预编译的,- #{}被替换成- ?占位符,可以避免 SQL 注入风险。
- ${}:本质是字符串拼接,不会进行自动类型转换,会将- ${}内的参数值直接插入到 SQL 语句中,所以容易引发 SQL 注入风险,使用时要确保传入的数据是安全的。所以上面写为- WHERE username = '${username}',需要双引号,传入- doubi变为- WHERE username = 'doubi',如果没有双引号会变为- WHERE username = doubi,SQL 会报错。
所以以后能用  #{} 就用  #{} ,除非 #{} 实现不了,才用 ${} 。
# 5.2 传递单个参数
还是以通过用户名查询用户的接口为例:
/**
 * 根据用户名查询用户
 */
User selectByUsername(String username);
2
3
4
在 UserMapper.xml 中通过 #{username} 获取参数,如下:
<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username}
</select>
2
3
4
但是其实发现下面这样也是可以的:
<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{aaa}
</select>
2
3
4
也就是说,传递单个参数,使用 #{} 或 ${} 接收参数的时候参数名不重要,可以是任意参数名,重要的是参数值。但是推荐见名知意,与接口中的变量名一致。
# 5.3 传递多个参数
如果传递多个参数,使用上面的方式就获取不到参数了。
如果传递多个参数,MyBatis 会将这些参数放到一个 Map 中,Map 的 key 有两种形式:arg0、arg1、...、argN 和 param1、param2、...、paramN 。
所以我们可以使用这两种 key 的形式,通过 #{} 或 ${} 来获取到参数。
举个栗子:
添加一个通过用户名和密码获取用户的接口:
UserMapper.java :
/**
 * 根据用户名和密码查询用户
 */
User selectByUsernameAndPassword(String username, String password);
2
3
4
那么在 UserMapper.xml 中,获取参数的方式如下:
<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{arg0} AND password = #{arg1}
</select>
2
3
4
或者使用 #{paramN} 的形式:
<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{param1} AND password = #{param2}
</select>
2
3
4
注意:param是从 1 开始。
#{argN} 和 #{paramN} 混着用也是可以的,因为它们在一个 Map 中,都可以获取到参数。
# 5.4 传递Map参数
既然 MyBatis 会将多个参数放到 Map 中,那么我们也可以传递一个 Map 作为参数,这样在 XxxMapper.xml 中就可以使用我们自己定义的 Map 中的 key 来获取参数了。
举个栗子:
定义一个通过 Map 查询的接口。
UserMapper.java :
/**
 * 根据Map查询用户
 */
User selectByMap(Map map);
2
3
4
那么在 UserMapper.xml 中,获取参数的方式如下:
<select id="selectByMap" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username} AND password = #{password}
</select>
2
3
4
待会在调用接口的时候,传递一个 Map,Map 中设置 key 为 username 和 password 。
在测试类中,创建测试方法,调用接口测试:
@Test
public void testSelectUserByMap() {
    // 获取SqlSession连接
    SqlSession sqlSession = MyBatisUtils.getSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("username", "doubi");
    map.put("password", "123456");
    // 查询用户
    User user = userMapper.selectByMap(map);
    log.info("user: {}", user);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 5.5 传递对象参数
在演示增删改查的时候,在插入和修改用户的时候已经使用了这种方式。
也就是传递参数对象时,在 Mapper.xml 中,只需要使用 #{} 或 ${}  ,以访问属性的方式获取参数即可。
还是将新增用户的例子搬到这里来:
在 UserMapper.java 中添加插入接口。
/**
 * 插入用户
 */
int insert(User user);
2
3
4
在 UserMapper.xml 中添加插入的 SQL 映射。
<insert id="insert">
    INSERT INTO tb_user (username, password, email, age, create_time, update_time)
    VALUES (#{username}, #{password}, #{email}, #{age}, #{createTime}, #{updateTime})
</insert>
2
3
4
参数通过 #{} 或  ${}  来获取传递的 User 对象中的属性。其实这里的属性对应的是 getter方法,不是成员变量。
# 5.6 使用@param命名参数
在传递多个参数的时候,在 Mapper.xml 中获取参数, key 为 arg0、arg1、...、argN 和 param1、param2、...、paramN 。
这样很不直观,我们可以使用 @param 注解,在接口中传递参数的时候指定 key 的名称。
举个栗子:
UserMapper.java 接口中传递参数,使用 @param 注解:
/**
 * 根据用户名和密码查询用户
 */
User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
2
3
4
在 UserMapper.xml 中获取参数, 就可以使用指定的 key 了:
<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username} AND password = #{password}
</select>
2
3
4
MyBatis 在处理这种方式,也是将参数放到 Map 中,只是 key 使用的是注解定义的 key,另外此时也是支持使用  param1、param2、...、paramN 这种方式来获取参数的,但是不支持 arg0、arg1、...、argN 这种方式。
在开发中,一般就使用两种方式就可以了:
- 使用 @param命名参数,不区分一个参数还是多个参数,都添加@param注解指定参数名称;
- 使用对象参数;
