动态SQL
动态SQL是Mybatis的强大特性之⼀,能够完成不同条件下不同的sql拼接
1. <if>标签
在注册用户的时候,可能会有这样⼀个问题,如下图所示:
注册分为两种字段:必填字段和非必填字段,那如果在添加用户的时候有不确定的字段传入,程序应该如何实现呢?
这个时候就需要使用动态标签来判断了,比如添加的时候性别gender为非必填字段,具体实现如下:
Integer insertUserByCondition(UserInfo userInfo);
Mapper.xml实现:
<insert id="insertUserByCondition"> INSERT INTO userinfo ( username, `password`, age, <if test="gender != null"> gender, </if> phone) VALUES ( #{username}, #{age}, <if test="gender != null"> #{gender}, </if> #{phone}) </insert>
注意test中的gender,是传入对象中的属性,不是数据库字段
Q:可不可以不进行判断,直接把字段设置为null呢?
A:不可以,这种情况下,如果gender字段有默认值,就会设置为默认值
2. <trim>标签
之前的插入用户功能,只是有⼀个gender字段可能是选填项,如果有多个字段,⼀般考虑使用标签结合标签,对多个字段都采取动态生成的方式。
标签中有如下属性:
- prefix:表示整个语句块,以prefix的值作为前缀
- suffix:表示整个语句块,以suffix的值作为后缀
- prefixOverrides:表示整个语句块要去除掉的前缀
- suffixOverrides:表示整个语句块要去除掉的后缀
调整Mapper.xml的插入语句为:
<insert id="insertUserByCondition"> INSERT INTO userinfo <trim prefix="(" suffix=")" suffixOverrides=","> <if test="username !=null"> username, </if> <if test="password !=null"> `password`, </if> <if test="age != null"> age, </if> <if test="gender != null"> gender, </if> <if test="phone != null"> phone, </if> </trim> VALUES <trim prefix="(" suffix=")" suffixOverrides=","> <if test="username !=null"> #{username}, </if> <if test="password !=null"> #{password}, </if> <if test="age != null"> #{age}, </if> <if test="gender != null"> #{gender}, </if> <if test="phone != null"> #{phone} </if> </trim> </insert>
3. <where>标签
看下⾯这个场景,系统会根据我们的筛选条件,动态组装where条件
需求:传入的用户对象,根据属性做where条件查询,用户对象中属性不为null的,都为查询条件
原有SQL:
SELECT * FROM userinfo WHERE age = 18 AND gender = 1 AND delete_flag =0
Mapper.xml实现
<select id="queryByCondition" resultType="com.example.demo.model.UserInfo"> select id, username, age, gender, phone, delete_flag, create_time,update_timefrom userinfo <where> <if test="age != null"> and age = #{age} </if> <if test="gender != null"> and gender = #{gender} </if> <if test="deleteFlag != null"> and delete_flag = #{deleteFlag} </if> </where> </select>
只会在子元素有内容的情况下才插入where子句,⽽且会⾃动去除子句的开头的AND或OR
以上标签也可以使用 替换,但是此种情况下,当子元素都没有内容时,where关键字也会保留
4. <set>标签
需求:根据传入的用户对象属性来更新用户数据,可以使用标签来指定动态内容.
接口定义:根据传入的用户id属性,修改其他不为null的属性
Integer updateUserByCondition(UserInfo userInfo);
Mapper.xml
<update id="updateUserByCondition"> update userinfo <set> <if test="username != null"> username = #{username}, </if> <if test="age != null"> age = #{age}, </if> <if test="deleteFlag != null"> delete_flag = #{deleteFlag}, </if> </set> where id = #{id} </update>
<set> :动态的在SQL语句中插入set关键字,并会删掉额外的逗号.(用于update语句中)
以上标签也可以使用 替换。
5. <foreach>标签
对集合进行遍历时可以使用该标签。标签有如下属性:
• collection:绑定方法参数中的集合,如List,Set,Map或数组对象
• item:遍历时的每⼀个对象
• open:语句块开头的字符串
• close:语句块结束的字符串
• separator:每次遍历之间间隔的字符串
需求:根据多个userid,删除用户数据
接口方法:
void deleteByIds(List<Integer> ids);
ArticleMapper.xml中新增删除sql:
<delete id="deleteByIds"> delete from userinfo where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete>
6. <include>标签
问题分析:
- 在xml映射文件中配置的SQL,有时可能会存在很多重复的片段,此时就会存在很多冗余的代码
我们可以对重复的代码片段进行抽取,将其通过 标签封装到⼀个SQL片段,然后再通过<include> 标签进行引用。
- :定义可重用的SQL片段
- :通过属性refid,指定包含的SQL片段
<sql id="allColumn"> id, username, age, gender, phone, delete_flag, create_time, update_time </sql>
通过 标签在原来抽取的地方进行引用。操作如下:
<select id="queryAllUser" resultMap="BaseMap"> select <include refid="allColumn"></include> from userinfo </select> <select id="queryById" resultType="com.example.demo.model.UserInfo"> select <include refid="allColumn"></include> from userinfo where id= #{id} </select>