# MyBatis教程 - 5 传递和获取参数

下面开始讲解在 XxxMapper.java 接口中传递参数,XxxMapper.xml 文件中获取参数。

# 5.1 获取参数值的两种方式

在通过用户名查询用户的时候,可以编写接口如下:

/**
 * 根据用户名查询用户
 */
User selectByUsername(String username);
1
2
3
4

在 UserMapper.xml 中通过 #{username} 获取参数,如下:

<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username}
</select>
1
2
3
4

除了使用 #{} 可以获取参数,还可以使用 ${} 获取参数。

<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = '${username}'
</select>
1
2
3
4

注意,${username} 本质是字符串拼接,所以需要加 '' ,拼接成 WHERE username = 'doubi' 这样的格式。

#{username} 会被替换为相应的参数值,并且根据参数的类型(例如 Stringint 等)自动处理值的格式,例如是 String 类型,会自动添加 ''


总结 #{}${} 的区别:

  • #{} :本质是占位符赋值,SQL 是预编译的,#{} 被替换成 ? 占位符,可以避免 SQL 注入风险。
  • ${} :本质是字符串拼接,不会进行自动类型转换,会将 ${} 内的参数值直接插入到 SQL 语句中,所以容易引发 SQL 注入风险,使用时要确保传入的数据是安全的。所以上面写为 WHERE username = '${username}' ,需要双引号,传入 doubi 变为 WHERE username = 'doubi' ,如果没有双引号会变为 WHERE username = doubi ,SQL 会报错。

所以以后能用 #{} 就用 #{} ,除非 #{} 实现不了,才用 ${}

# 5.2 传递单个参数

还是以通过用户名查询用户的接口为例:

/**
 * 根据用户名查询用户
 */
User selectByUsername(String username);
1
2
3
4

在 UserMapper.xml 中通过 #{username} 获取参数,如下:

<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username}
</select>
1
2
3
4

但是其实发现下面这样也是可以的:

<select id="selectByUsername" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{aaa}
</select>
1
2
3
4

也就是说,传递单个参数,使用 #{}${} 接收参数的时候参数名不重要,可以是任意参数名,重要的是参数值。但是推荐见名知意,与接口中的变量名一致。

# 5.3 传递多个参数

如果传递多个参数,使用上面的方式就获取不到参数了。

如果传递多个参数,MyBatis 会将这些参数放到一个 Map 中,Map 的 key 有两种形式:arg0、arg1、...、argNparam1、param2、...、paramN

所以我们可以使用这两种 key 的形式,通过 #{}${} 来获取到参数。


举个栗子:

添加一个通过用户名和密码获取用户的接口:

UserMapper.java

/**
 * 根据用户名和密码查询用户
 */
User selectByUsernameAndPassword(String username, String password);
1
2
3
4

那么在 UserMapper.xml 中,获取参数的方式如下:

<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{arg0} AND password = #{arg1}
</select>
1
2
3
4

或者使用 #{paramN} 的形式:

<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{param1} AND password = #{param2}
</select>
1
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);
1
2
3
4

那么在 UserMapper.xml 中,获取参数的方式如下:

<select id="selectByMap" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username} AND password = #{password}
</select>
1
2
3
4

待会在调用接口的时候,传递一个 Map,Map 中设置 key 为 usernamepassword


在测试类中,创建测试方法,调用接口测试:

@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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 5.5 传递对象参数

在演示增删改查的时候,在插入和修改用户的时候已经使用了这种方式。

也就是传递参数对象时,在 Mapper.xml 中,只需要使用 #{}${} ,以访问属性的方式获取参数即可。


还是将新增用户的例子搬到这里来:

在 UserMapper.java 中添加插入接口。

/**
 * 插入用户
 */
int insert(User user);
1
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>
1
2
3
4

参数通过 #{}${} 来获取传递的 User 对象中的属性。其实这里的属性对应的是 getter方法,不是成员变量。

# 5.6 使用@param命名参数

在传递多个参数的时候,在 Mapper.xml 中获取参数, key 为 arg0、arg1、...、argNparam1、param2、...、paramN

这样很不直观,我们可以使用 @param 注解,在接口中传递参数的时候指定 key 的名称。

举个栗子:

UserMapper.java 接口中传递参数,使用 @param 注解:

/**
 * 根据用户名和密码查询用户
 */
User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
1
2
3
4

在 UserMapper.xml 中获取参数, 就可以使用指定的 key 了:

<select id="selectByUsernameAndPassword" resultType="User">
    SELECT * FROM tb_user
    WHERE username = #{username} AND password = #{password}
</select>
1
2
3
4

MyBatis 在处理这种方式,也是将参数放到 Map 中,只是 key 使用的是注解定义的 key,另外此时也是支持使用 param1、param2、...、paramN 这种方式来获取参数的,但是不支持 arg0、arg1、...、argN 这种方式。


在开发中,一般就使用两种方式就可以了:

  • 使用 @param 命名参数,不区分一个参数还是多个参数,都添加 @param 注解指定参数名称;
  • 使用对象参数;