if
if标签能够有条件地包含 where 子句的一部分。
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
如果传入的title参数不是null就会启用and之后的查询条件。
也可以插入多个if 标签。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
根据判断类型的不同,用法也不同。
1、数字类型
<if test="id != null"></if>
<if test='id != null and id > 28'></if>
<if test='id != null and id gt 28'></if>
一般不推荐第二种用法,因为在if标签中<是不能使用的。建议用字母代替。
字母 | 符号 |
---|---|
gt | > |
gte | >= |
lt | < |
lte | <= |
2、字符串
不用过滤空串:
<if test="username != null"></if>
过滤空串:
<if test="username != null and '' != username"></if>
判断字符串是否以某字符开头,或者包含某字符:
<if test="username != null and username.indexOf('ji') == 0"> </if> <!-- 是否以什么开头 -->
<if test="username != null and username.indexOf('ji') >= 0"> </if> <!-- 是否包含某字符 -->
判断是否是某个特殊的字符串:
<if test="username != null and 'hello' == username"></if>
<if test="username != null and 'hello'.toString() == username.toString()"></if> <!--当参数不是字符串的时候需要这么做-->
3、判断list和map是否为空
<if test="userList != null and userList.isEmpty()"></if>
choose,when,otherwise
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
where,set,trim
在上面的例子中,如果把state=‘ACTIVE’也设置成动态语句,则会出现问题。自动生成的where查询子句中可能会以and开头,系统直接报错。
一种解决方法是在前面加上1=1这个恒成立的条件,但这不是长远之计,做法也很不优美。
我们通过where标签来解决这个问题。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where 元素知道只有在一个以上的if条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
类似的,update的set也可以这么做。
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
trim是自定义的一种解决方式,它有四个属性。
属性 | 描述 |
---|---|
prefix | 给sql语句拼接的前缀 |
suffix | 给sql语句拼接的前缀 |
prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定 |
suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |
譬如上面的where标签可以被如下的trim代替:
<trim prefix="WHERE" prefixOverrides="AND">
...
</trim>
set标签可以被如下的trim代替:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
还可以自定义:
<insert id="selectRole">
INSERT INTO role
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="rolename!=null">
role_name,
</if>
<if test="note!=null">
note
</if>
</trim>
<trim prefix="VALUES(" suffix=")" suffixOverrides=",">
<if test="rolename!=null">
#{rolename}
</if>
<if test="note!=null">
#{note}
</if>
</trim>
</insert>
foreach
有时我们需要对一个集合进行遍历,通常是在构建 IN 条件语句或者是VALUES等关键词的时候。
先看一个简易的例子:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
下面介绍一下基本属性:
属性 | 描述 |
---|---|
item | 集合中元素迭代时的别名,该参数为必选。 |
index | 在list和数组中,index是元素的序号;在map中,index是元素的key。该参数可选。 |
open | foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选。 |
separator | 元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。 |
close | foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。 |
collection | 要做foreach的对象。List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。 |
我们着重谈一下collection。如果参数是单一的且是List或者array,只要用“list”和“array”。如果有多个参数,可以使用@Param(“value”)来指定这个list或者array的名称,collection只要用value代替即可。
还有一种处理方法是直接传入一个map类型的对象,其中key是参数名,而value就是具体对象了。
HashMap<String,Object> t = new HashMap<String, Object>();
List<Blog> li=new List<Blog>;
...
t.put("id",1);
t.put("title","myblog");
t.put("names",li);
这就起到了和@Param一样的作用,在映射文件中直接用id,title和names就行。
@Param可以用传入一个map来代替。
bind
<select id="selectById" resultType="Users">
<bind name="abc" value="id"/>
select * from users where id = #{abc}
</select>
bind标签中,value对应传入实体类的某个字段,name属性既给对应字段取的变量名。在value属性中可以使用字符串拼接等特殊处理。
<select id="selectById" resultType="Users">
<bind name="abc" value="'%'+ id + '%'"/>
select * from users where id like #{abc}
</select>