MyBatis - 动态SQL
前言
我们在某网站填写个人信息时,时常会遇到可以选填的空(即可填,可不填),由于之前讲过的Java中的SQL语句都是固定的,且我们不可能对所有情况都写出与之对应的插入语句(太过繁琐),所以这里就引入了动态SQL。
一,<if>标签
可以通过判断当前传入的参数是否为null,来删减对应的参数。
@Mapper
public interface UserInfoXmlMapper {Integer insertUserInfo(UserInfo userInfo);
}
<insert id="insertUserInfo" useGeneratedKeys="true" keyProperty="id">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>
二,<trim> 标签
但是如果光使用<if>标签可能会出现错误,比如:
<insert id="insertUserInfo" useGeneratedKeys="true" keyProperty="id">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>
这时就要使用<trim>标签,该标签有四个属性:
- prefix:表示整个语句块,以 prefix 的值作为前缀
- suffix:表示整个语句块,以 suffix 的值作为后缀
- prefixOverrides:表示整个语句块要删去的前缀
- suffixOverrides:表示整个语句块要删去的后缀
<insert id="insertUserInfo" useGeneratedKeys="true" keyProperty="id">insert into userInfo<trim prefixOverrides="," 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><if test="phone!=null">phone</if></trim>values<trim prefixOverrides="," 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><if test="phone!=null">#{phone}</if></trim></insert>
解释各个属性的作用:
- prefix:在开始部分加上(
- suffix:在结束部分加上 )
- prefixOverrides:如果在所以<if>标签中内容拼接之后,以 ',' 开头,那么就将它删除
- suffixOverrides:如果在所以<if>标签中内容拼接之后,以 ',' 结尾,那么就将它删除
后两个属性就避免出现上述SQL语句的问题
三,<where> 标签
在where条件查询中,我们的查询条件也有可能为null,所以也需要用到<if>标签,也就是说这里也会出现上述问题,只不过这里多出来的是and / or,这时就需要使用<where>标签来帮我们删除where语句开头的 and / or。注:虽然使用<trim>标签也能达到上述效果,但是如果where查询中的所有参数都为 null 时,<where>标签能将自己本身给删除,而<trim>标签仍会保留where。
<select id="queryUserList" resultType="com.example.javaeespringioc.controller.UserInfo">select * from userInfo<where><if test="username!=null">username = #{username}</if><if test="gender!=null">and gender = #{gender}</if></where></select>
四,<set> 标签
<set>标签也是删除因<if>标签产生的多余的 ',' ,它是可以使用<trim>标签替代的
<update id="updateUserInfo">update userInfo<set><if test="username!=null">username = #{username},</if><if test="password!=null">password = #{password}</if></set>where id = #{id}</update>
五,<foreach>标签
我们SQL中有这样的语句:delete from userinfo where id in (1,2,3,4,5),这无法使用之前的内容来表示,这时就会用到<foreach>标签,它有以下5个属性:
- collections:绑定参数中集合,如 List,Set,Map 或 数组对象
- item:遍历集合中的对象,类似于Java中,for(int x : nums) 中的 x
- open:语句开头的字符串
- close:语句结尾的字符串
- separator:每个元素之间使用separator间隔开来
<delete id="deleteUserInfo">delete from userInfo where id in<foreach collection="idx" item="id" separator="," open="(" close=")">#{id}</foreach></delete>
六,<include>标签
xml中的配置的SQL语句可能会存在很多重复的片段,我们可以对重复的片段进行抽取,通过<sql>标签进行封装,然后再通过<include>标签进行引用。
<sql id="allColumn">id, username, password, age, gender, phone</sql><select id="queryUserList" resultType="com.example.javaeespringioc.controller.UserInfo">select<include refid="allColumn"></include>from userInfo<where><if test="username!=null">username = #{username}</if><if test="gender!=null">and gender = #{gender}</if></where></select>
七,<script>标签
上述6个标签都是通过.xml文件来实现动态SQL,那么我们注解如何来实现动态SQL呢?就是使用<script>标签,代码如下:
@Select("<script>" +"select * from userInfo " +"<where>" +"<if test='username!=null'>" +"username = #{username} " +"</if>" +"<if test='gender!=null'>" +"and gender = #{gender}" +"</if>" +"</where>" +"</script>")List<UserInfo> queryBy(@Param("username") String username, @Param("gender") Integer gender);
注意:注解中的是字符串,所以要注意字符串拼接时的空格,单双引号的问题。且使用注解方式如果出错,报错信息不会告诉你哪里出问题了,所以不推荐使用该方法!!!