目录
一、什么是动态SQL
MyBatis 是一个流行的持久层框架,用于在 Java 应用程序中与数据库进行交互。动态 SQL 是 MyBatis 提供的一种强大功能,它允许开发者在 SQL 查询中根据条件动态地生成不同的 SQL 语句。这种功能使得 SQL 更加灵活和可维护,尤其是在需要根据多种条件来构建查询的情况下。
动态 SQL 查询的核心在于可以根据不同的输入参数或者条件,动态地调整 SQL 语句的结构。例如,可以根据某些参数决定是否包含某个 SQL 片段,生成 WHERE 子句,或者选择性地加入不同的字段等。
如当你注册个人信息时,有些选项是必填如你的姓名、电话号码等,而有些选项是选填如你的爱好、喜欢的颜色等。这个时候就需要你填入的信息是一个空即' ',而不是一个 null ,这个时候就会使用到动态 SQL 。
创建一个数据表 userinfo 以这个表来进行演示,其中 photo 字段为,当没有显式指定一个字段时将默认赋值为一个空值,如下代码所示:
mysql> create table userinfo(
-> id int primary key auto_increment,
-> username varchar(100) not null,
-> password varchar(30) not null,
-> photo varchar(500) default '');
Query OK, 0 rows affected (0.02 sec)
mysql> insert into userinfo(id,username,password,photo) values
-> (1,"zhangsan","123","cat.png"),
-> (2,"lisi","456","");
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from userinfo;
+----+----------+----------+---------+
| id | username | password | photo |
+----+----------+----------+---------+
| 1 | zhangsan | 123 | cat.png |
| 2 | lisi | 456 | |
+----+----------+----------+---------+
2 rows in set (0.00 sec)
此外 MyBatis 项目里应有:
实体类 UserInfo
@Data
public class UserInfo {
private int id;
private String username;
private String password;
private String photo;
}
接口 UserMapper
@Mapper
public interface UserMapper {
}
以及 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserMapper">
</mapper>
二、动态SQL的使用
2.1 if标签
<if></if>标签:用于满足指定条件时包含的某段 sql 语句。
UserMapper 接口:
@Mapper
public interface UserMapper {
int insert(UserInfo userInfo);
}
UserMapper.xml :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserMapper">
<insert id="insert">
insert into userinfo(id,username,password
<if test="photo!=null">
,photo
</if>
)values(#{id},#{username},#{password}
<if test="photo!=null">
,#{photo}
</if>
)
</insert>
</mapper>
上述代码中 <if> 标签的 test 是满足某个条件时则执行 <if> 标签内的内容,如不满足则不执行,因此当我们需要某个字段添加时某个字段不添加时则会用到 <if> 标签,如下场景:
@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
UserInfo userInfo = new UserInfo();
userInfo.setId(3);
userInfo.setUsername("Bob");
userInfo.setPassword("787");
userInfo.setPhoto("dog.png");
int ret = userMapper.insert(userInfo);
System.out.println("执行了:"+ret+"条操作");
}
}
结果为:
当某条属性未添加时,新添记录中那条属性则为空:
@Test
void testInsert() {
UserInfo userInfo = new UserInfo();
userInfo.setId(4);
userInfo.setUsername("Ali");
userInfo.setPassword("777");
int ret = userMapper.insert(userInfo);
System.out.println("执行了:"+ret+"条操作");
}
结果为:
2.2 trim标签
<trim></trim>标签:当某些选项是非必选时,则可以用到 <trim> 标签和 <if></if> 标签的结合体来完成操作。
- prefix:表示整个语句块,以prefix的值作为前缀
- suffix:表示整个语句块,以suffix的值作为后缀
- prefixOverrides:表示整个语句块要去除掉的前缀
- suffixOverrides:表示整个语句块要去除掉的后缀
UserMapper 接口:
int insert2(UserInfo userInfo);
UserMapper.xml:
<insert id="insert2">
insert into userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username!=null">
username,
</if>
<if test="password!=null">
password,
</if>
<if test="photo!=null">
photo,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username!=null">
#{username},
</if>
<if test="password!=null">
#{password},
</if>
<if test="photo!=null">
#{photo},
</if>
</trim>
</insert>
测试:
@Test
void insert2() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("laoliu");
userInfo.setPassword("666");
int ret = userMapper.insert2(userInfo);
System.out.println("执行了:"+ret+"条操作");
}
结果为:
通过上述代码我们可以了解到 xml 文件中的 <trim prefix="(" suffix=")" suffixOverrides=","> 代表着开头为(、结尾为)、整个语句块要去除掉的后缀为,。
2.3 where标签
<where>标签:会自动添加“where”关键字,并在必要时省去前置的“and”或“or”。
UserMapper接口:
List<UserInfo> selectAllByWhere(UserInfo userInfo);
UserMapper.xml:
<select id="selectAllByWhere" resultType="com.example.demo.model.UserInfo">
select * from userinfo
<where>
<if test="id>0">
and #{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
<if test="photo!=null">
and photo=#{photo}
</if>
</where>
</select>
@Test
void selectAllByWhere() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("zhangsan");
userInfo.setPassword("123");
List<UserInfo> list = userMapper.selectAllByWhere(userInfo);
System.out.println(list);
}
通过上述代码,我们可以了解到非必传条件可用到 where,而且 where 如果有满足条件的语句的话会默认去除最前面的 and 或 or。
结果为:
<trim>标签与<if>标签的结合也可替换上述的<where>标签:
<trim prefix="where" prefixOverrides="and">
<if test="id>0">
and #{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
<if test="photo!=null">
and photo=#{photo}
</if>
</trim>
2.4 set标签
<set>标签:用于“update”语句,自动添加“set”关键字并省去多余的逗号
UserMapper接口:
int upDateById(UserInfo userInfo);
UserMapper.xml:
<update id="upDateById">
update userinfo
<set>
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="photo!=null">
photo=#{photo}
</if>
</set>
where id=#{id}
</update>
测试:
@Test
void upDateById() {
UserInfo userInfo = new UserInfo();
userInfo.setId(5);
userInfo.setUsername("laoba");
userInfo.setPassword("868");
int ret = userMapper.upDateById(userInfo);
System.out.println("执行了:"+ret+"条语句");
}
结果为:
2.5 foreach标签
<foreach>标签:用于迭代集合,比如列表或数组,生成一段 sql 代码。对集合进⾏遍历时可以使⽤该标签。<foreach>标签有如下属性:
- collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
- item:遍历时的每⼀个对象
- open:语句块开头的字符串
- close:语句块结束的字符串
- separator:每次遍历之间间隔的字符串
UserMapper接口:
int deleteById(List<Integer> ids);
UserMapper.xml:
<delete id="deleteById">
delete from userinfo where id in
<foreach collection="ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</delete>
测试:
@Test
void deleteById() {
List<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(5);
int ret = userMapper.deleteById(list);
System.out.println("执行了:"+ret+"条操作");
}
结果为:
本期博文到这里就结束了,希望各位有所收获。