🌲动态SQL
动态SQL是Mybatis的强⼤特性之⼀,通过一系列标签能够完成不同条件下不同的sql拼接。
接下来为大家介绍一些标签来完成sql拼接
首先我们准备数据库userinfo表如下:
🍃< if >标签
在我们实际生活中,当我们在注册时,有时候会面临以下情况
注册分为两种字段:必填字段和⾮必填字段
那如果在添加⽤⼾的时候有不确定的字段传⼊,程序应该如何实现呢?
这个时候就需要使⽤动态标签来判断了,⽐如添加的时候性别gender(性别)为⾮必填字段,具体实现如下
我们这里先采用xml方式进行操作:
接口定义如下:
Integer insertUserByCondition(UserInfo userInfo);
XML代码实现:
<insert id="insertUserByCondition"> INSERT INTO userinfo ( username, password, age, <if test="gender != null"> gender, </if> phone) VALUES ( #{username}, #{password}, #{age}, <if test="gender != null"> #{gender}, </if> #{phone}) </insert>
使用测试单元进行测试:
@Test void insertUserByCondition() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("天帅星"); userInfo.setPassword("123"); userInfo.setAge(20); //userInfo.setGender(1); userInfo.setPhone("123456789"); int count = dynamicSqlMapper.insertUserByCondition(userInfo); System.out.println("改变行数为:" + count); }
启动测试单元:
我们可以看到,查询字段已经没有gender选项了
我们再次查询数据库,看是否插入成功
我们可以看到查询成功。
如果我们选择使用注解的方式的话,我们需要把上⾯SQL(包括标签),使⽤ 标签括起来就可以
使用如下:
@Insert("<script>" + "INSERT INTO userinfo (username,`password`,age," + "<if test='gender!=null'>gender,</if>" + "phone)" + "VALUES(#{username},#{password},#{age}," + "<if test='gender!=null'>#{gender},</if>" + "#{phone})"+ "</script>") Integer insert(UserInfo userInfo);
测试单元代码如下:
@Test void insert() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("koukou星"); userInfo.setPassword("1231"); userInfo.setAge(22); //userInfo.setGender(1); userInfo.setPhone("1234"); int count = dynamicSqlMapper.insertUserByCondition(userInfo); System.out.println("改变行数为:" + count); }
启动测试单元:
我们可以发现,与上面使用XML效果是一样的。
查验数据库是否插入成功:
也插入成功
但是呢,博主这里推荐使用XML方式,因为不容易出错。接下来博主的演示也全部使用XML的方式。
🌳< trim >标签
上面的插⼊⽤⼾功能,只是有⼀个gender字段可能是选填项,如果有多个字段,就会出现问题。
比如以下程序:
<insert id="insert2"> INSERT INTO userinfo( <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>) VALUES( <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>) </insert>
测试单元代码如下:
@Test void insert2() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("天仇星"); userInfo.setPassword("11"); userInfo.setAge(33); userInfo.setGender(1); //userInfo.setPhone("1234"); int count = dynamicSqlMapper.insert2(userInfo); System.out.println("改变行数为:" + count); }
启动测试单元
我们发现了报错,上面的sql语句后面多了一个 , 导致查询失败
这时候我们就需要使用标签结合标签,对多个字段都采取动态⽣成的⽅式
< trim >标签中有如下属性:
- prefix:表⽰整个语句块,以prefix的值作为前缀
- suffix:表⽰整个语句块,以suffix的值作为后缀
- prefixOverrides:表⽰整个语句块要去除掉的前缀
- suffixOverrides:表⽰整个语句块要去除掉的后缀
那么上述问题代码便可以修改如下:
<insert id="insert2"> 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>
在以上sql动态解析时,会将第⼀个部分做如下处理:
- 基于 prefix 配置,开始部分加上 (
- 基于 suffix 配置,结束部分加上 )
- 多个组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于suffixOverrides 配置去掉最后⼀个 ,
🎍< where >标签
当我们需要对多个字段进行查询时。
需求:传⼊的⽤⼾对象,根据属性做where条件查询,⽤⼾对象中属性不为 null 的,都为查询条件.如username为"a",则查询条件为where username=“a”
如果我们只使用上面的两种标签,是无法达到效果的。这时候就需要where标签了
XML相关代码如下:
<select id="select" resultType="com.example.demo.model.UserInfo"> select id, username, age, gender, phone, delete_flag, create_time, update_time from 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 > 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或OR
🍀< set >标签
需求:根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤< set >标签来指定动态内容.
<update id="update"> 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语句中)
🌴< foreach >标签
对集合进⾏遍历时可以使⽤该标签。标签有如下属性:
- collection:绑定⽅法参数中的集合,如List,Set,Map或数组对象
- item:遍历时的每⼀个对象
- open:语句块开头的字符串
- close:语句块结束的字符串
- separator:每次遍历之间间隔的字符串
需求:根据多个userid,删除⽤⼾数据
比如我们又以下接口:
void deleteByIds(List<Integer> ids);
那么我们批量删除的语句就如下:
<delete id="delete"> delete from userinfo where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete>
🎋< include >标签
在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码
我们可以对重复的代码⽚段进⾏抽取,将其通过 < sql > 标签封装到⼀个SQL⽚段,然后再通过< include > 标签进⾏引⽤。
- < sql > :定义可重⽤的SQL⽚段
- < include > :通过属性refid,指定包含的SQL⽚段
抽取如下:
<sql id="allColumn"> id, username, age, gender, phone, delete_flag, create_time, update_time </sql>
通过 < include > 标签在原来抽取的地⽅进⾏引⽤。操作如下:
<select id="queryAllUser" resultMap="BaseMap"> select <include refid="allColumn"></include> from userinfo </select>
⭕总结
关于《【JavaEE进阶】 MyBatis之动态SQL》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!