前言
我们在某网站填写个人信息时,时常会遇到可以选填的空(即可填,可不填),由于之前讲过的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);
注意:注解中的是字符串,所以要注意字符串拼接时的空格,单双引号的问题。且使用注解方式如果出错,报错信息不会告诉你哪里出问题了,所以不推荐使用该方法!!!