# MyBatis教程 - 7 特殊SQL的执行
下面来介绍一下 MyBatis 中,一些特殊 SQL 的执行,下面这些情况,和普通的处理有些区别。
# 7.1 模糊查询
在前面我们推荐能使用 #{}
的地方就不要使用 ${}
,但是模糊查询这种场景,直接使用 #{}
就无法解决,下面有三种处理方式。
举个栗子:
根据用户名模糊查询,定义接口,UserMapper.java
如下:
/**
* 根据用户名模糊查询用户
*/
List<User> selectByUsernameLike(@Param("username") String username);
2
3
4
定义 SQL 映射,UserMapper.xml
如下:
<select id="selectByUsernameLike" resultType="User">
SELECT * FROM tb_user
WHERE username LIKE '%#{username}%'
</select>
2
3
4
但是直接写 '%#{username}%'
,在执行的时候是会报错的,通过日志发现,执行的 SQL 是:SELECT * FROM tb_user WHERE username LIKE '%?%'
,因为 #{}
使用的是占位符的方式,所以 '%?%'
被处理成了字符串。
针对模糊查询,下面有三种处理方式。
# 1 使用${}拼接
UserMapper.xml
:
<select id="selectByUsernameLike" resultType="User">
SELECT * FROM tb_user
WHERE username LIKE '%${username}%'
</select>
2
3
4
直接使用 ${username}
就可以解决。
# 2 使用contact拼接
UserMapper.xml
:
<select id="selectByUsernameLike" resultType="User">
SELECT * FROM tb_user
WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
2
3
4
使用 CONCAT
进行字符串拼接,这样就可以将 %
和 #{username}
拼接起来。
# 3 使用双引号(推荐)
UserMapper.xml
:
<select id="selectByUsernameLike" resultType="User">
SELECT * FROM tb_user
WHERE username LIKE "%"#{username}"%"
</select>
2
3
4
注意 %
左右都有双引号。
推荐使用这种方式。
# 7.2 批量删除
有时候批量删除元素,使用的是将ID或条件拼接起来,然后使用 in
来进行删除。
例如根据多个用户名删除用户,那么 SQL 如下:
DELETE FROM tb_user WHERE username in ('doubi','niubi')
使用 MyBatis 定义接口如下,在 UserMapper.java 中:
/**
* 批量删除用户信息
*/
int deleteByUsernames(@Param("usernames") String usernames);
2
3
4
那么对应的 UserMapper.xml 编写如下:
<delete id="deleteMore">
DELETE FROM tb_user
WHERE username in (${usernames})
</delete>
2
3
4
这里需要使用 ${}
,只需要传递 'doubi','niubi'
格式的参数,自己添加引号即可。
不能使用 #{}
了,因为参数是字符串, #{}
会自动在最外层添加引号,变成 ''doubi','niubi''
。
所以编写测试方法如下:
@Test
public void deleteMore() {
// 获取SqlSession连接
SqlSession sqlSession = MyBatisUtils.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
String usernames = "'doubi','niubi'"; // 传递多个用户名
// 删除用户
int result = userMapper.deleteByUsernames(usernames);
log.info("result: {}", result);
}
2
3
4
5
6
7
8
9
10
11
12
注意:这里值针对字符串类型的字段,使用 in
来删除,如果是整形的ID,那么直接使用 String ids = "1,2";
即可,不用引号。
后面在动态SQL章节,会通过foreach标签来讲解批量删除。
# 7.3 动态设置表名
有时候,一张表的数据太多了,我们会进行数据的拆分,将数据保存在多张表中,这个时候查询数据库,我们就需要将表的名称也传递给 XxxMapper.xml 映射文件。
使用 #{}
传递字符串类型,会自动添加上 ''
,但是表的名称在 SQL 中是不能用引号 ''
括起来的,所以这个时候只能使用 ${}
。
举个栗子:
根据表名和用户名查询用户,UserMapper.java
:
/**
* 根据表名和用户名查询用户信息
*/
List<User> selectByTableName(@Param("tableName") String tableName, @Param("username") String username);
2
3
4
对应的 UserMapper.xml
的 SQL 映射如下:
<select id="selectByTableName" resultType="User">
SELECT * FROM ${tableName}
WHERE username = #{username}
</select>
2
3
4
这样就可以实现动态的设置表名称。
测试的时候可以传递表的名称:
String tableName = "tb_user";
String username = "doubi";
// 查询用户列表
List<User> userList = userMapper.selectByTableName(tableName, username);
2
3
4
5
# 7.4 获取自增的主键ID值
在实际的开发中,经常会遇到这样的情况,就是两张表存在关联,一张表中有一列外键,存储另一张表的ID。
在插入数据的时候,可能会存在同时插入两张表的数据,此时就需要知道插入后,数据的主键ID,这样好把 ID 作为外键保存到另一张表中。
下面就介绍一下如何获取插入后的自增主键的ID值。
UserMapper.java
:
/**
* 插入用户信息
*/
int insert(User user);
2
3
4
接口是没有变化的,返回值并不是主键的ID,返回值表示插入数据的条目数。
所以需要修改 SQL 映射文件,UserMapper.xml
:
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO tb_user (username, password, email, age, create_time, update_time)
VALUES (#{username}, #{password}, #{email}, #{age}, #{createTime}, #{updateTime})
</insert>
2
3
4
useGeneratedKeys="true"
来告诉MyBatis这个插入操作可能会生成一个键值;- 通过
keyProperty
属性指定一个Java对象的属性名,MyBatis会将生成的主键ID值设置到这个Java对象的属性中。也就是插入的时候,传入了一个 User 对象,keyProperty="id"
表示插入完成后,MyBatis 会将生成的主键 ID 设置到 User 对象的id
属性。
编写测试方法:
@Test
public void testInsertUser() {
// 获取SqlSession连接
SqlSession sqlSession = MyBatisUtils.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("foooor");
user.setPassword("123456");
user.setEmail("foooor@qq.com");
user.setAge(20);
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
// 插入用户
int result = userMapper.insert(user);
log.info("user id: {}", user.getId()); // 可以获取到插入后的ID
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这样就可以获取到插入后的自增主键的ID了。
← 06-查询结果 08-多对一和一对多 →