Mybatis动态SQL的官方文档: https://mybatis.net.cn/dynamic-sql.html
动态SQL
动态SQL是 MyBatis的强大特性之一,如果是使用JDBC根据不同条件拼接sql很麻烦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
if标签
使用场景:在我们数据库表中字段分为必填字段和非必填字段,对与非必填字段数据库会自动帮我们赋值,那如果在添加用户的时候有不确定的字段传入,程序应该如何实现呢?
这个时候就需要使用动态标签来判断了,比如添加的时候性别gender为非必填字段
<insert id="insertUserByCondition">
INSERT INTO user_info (
username,
age,
<if test="gender != null">
gender,
</if>
password)
VALUES (
#{username},
#{age},
<if test="gender != null">
#{gender},
</if>
#{password})
</insert>
可不可以不进行判断,直接把字段设置为null呢?
不可以,这种情况下,如果gender字段有默认值,就会设置为默认值
测试代码
@Test
void insertUserByCondition() {
UserInfo userInfo=new UserInfo();
userInfo.setUsername("username5");
userInfo.setPassword("password5");
userInfo.setGender(5);
userInfo.setAge(5);
userInfoMapperXML.insertUserByCondition(userInfo);
}
不设置gender的参数,也可以进行插入
注意:
- if标签test中的属性是传入对象中的属性,不是数据库字段
- 插入语句中,values中赋值也要有if标签,要一一对应,gender字段中有if标签,values中也要的gender属性也要有if标签
trim标签
标签中有如下属性:
• prefix:表示整个语句块,以prefix的值作为前缀
• suffix:表示整个语句块,以suffix的值作为后缀
• prefixOverrides:表示整个语句块要去除掉的前缀
• suffixOverrides:表示整个语句块要去除掉的后缀
trim标签的使用
sql语句
insert into user_info ( username, password, age, gender ) values("username5","password5",5,5)
insert into user_info
<trim suffixOverrides="," prefix="(" suffix=")">
<if test="username!=null">
username,
</if>
<if test="password!=null">
password,
</if>
<if test="age!=null">
age,
</if>
<if test="gender!=null">
gender
</if>
</trim>
values (
<trim suffixOverrides="," prefix="(" suffix=")">
<if test="username!=null">
#{username},
</if>
<if test="password!=null">
#{password},
</if>
<if test="age!=null">
#{age},
</if>
<if test="gender!=null">
#{gender}
</if>
</trim>
)
</insert>
测试代码
@Test
void insertUserByCondition() {
UserInfo userInfo=new UserInfo();
userInfo.setUsername("username5");
userInfo.setPassword("password5");
userInfo.setGender(5);
userInfo.setAge(5);
userInfoMapperXML.insertUserByCondition(userInfo);
}
where标签
看下⾯这个场景,系统会根据我们的筛选条件,动态组装where条件
这个是怎么实现的呢?通过where标签
举个例子
sql语句:
select* from user_info where age=1 and gender =2;
<select id="selectByCondition" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time,
update_time
from user_info where
<if test="age != null">
age = #{age}
</if>
<if test="gender != null">
and gender = #{gender}
</if>
</select>
当if标签有一个或两个不符合条件的时候,会报错,这时候where标签就派上用场了
<select id="selectByCondition" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time,
update_time
from user_info where
<where>
<if test="age != null">
age = #{age}
</if>
<if test="gender != null">
and gender = #{gender}
</if>
</where>
</select>
测试代码
@Test
void selectByCondition() {
UserInfo userInfo=new UserInfo();
userInfo.setAge(16);
userInfoMapperXML.selectByCondition(userInfo);
}
where标签只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
set标签
sql
update user_info set password="123" ,gender= 4 where id=34
<update id="updateUser2">
update user_info set
<if test="username!=null">
username=#{username}
</if>
<if test="password!=null">
,password=#{password}
</if>
<if test="gender!=null">
,gender=#{gender}
</if>
where id=#{id}
</update>
如果我们写出这样的xml文件,当我们的username为null时,sql语法错误,多了一个逗号
下面是报错信息
set标签会删除额外的逗号,并把set插入sql语句中
<update id="updateUser2">
update user_info
<set>
<if test="username!=null">
username=#{username}
</if>
<if test="password!=null">
,password=#{password}
</if>
<if test="gender!=null">
,gender=#{gender}
</if>
</set>
where id=#{id}
</update>
测试代码
@Test
void updateUser2() {
UserInfo userInfo=new UserInfo();
userInfo.setPassword("123");
userInfo.setGender(4);
```java
userInfo.setId(34);
userInfoMapperXML.updateUser2(userInfo);
}
foreach标签
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集在这里插入代码片
合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符!
foreach 标签有如下属性:
collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每⼀个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
举个例子:批量查询id为12,13,14的数据
sql:
select * from user_info where id in ( 12 , 13 ,14)
<select id="selectUserByIds" resultType="com.example.demo.model.UserInfo">
select * from user_info where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
测试代码
@Test
void selectUserByIds() {
List<Integer> ids=new ArrayList<>();
ids.add(12);
ids.add(13);
ids.add(14);
userInfoMapperXML.selectUserByIds(ids);
}
需求:批量删除id为12,13,14的数据
<delete id="deleteByIds">
delete from user_info where id in
<foreach collection="ids" item="id" separator="," open="(" close=")" >
#{id}
</foreach>
</delete>
测试代码
@Test
void deleteByIds() {
List<Integer> ids=List.of(12,13,14);
userInfoMapperXML.deleteByIds(ids);
}
include标签和sql标签
在xml映射文件中配置的SQL,有时可能会存在很多重复的片段,此时就会存在很多冗余的代码
sql 标签: 定义可重用的SQL片段
include 标签:通过属性refid,指定包含的SQL片段
<sql id="allColumn">
id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>
<select id="selectAll" resultType="com.example.demo.model.UserInfo">
SELECT
<include refid="allColumn"></include>
FROM `user_info`
</select>
测试代码
@Test
void selectAll() {
userInfoMapperXML.selectAll().stream().forEach(x-> System.out.println(x));
}