# 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
注解指定参数名称; - 使用对象参数;