多条件查询
动态SQL是MyBatis的一个强大特性。在使用JDBC操作数据时,如果查询条件特别多,将条件串联SQL字符串是一件痛苦的事情。通常的解决方法是写很多的if-else条件语句对字符串进行拼接,并确保不能忘了空格或在字段的最后省略逗号。MyBatis使用强大的动态SQL来改善这种情形。动态SQL是基于OGNL的表达式,可方便我们在SQL语句中实现某些逻辑。
1.使用if+where元素实现多条件查询用户列表操作。
2.使用if+trim元素实现多条件查询用户列表操作。
if+where
1.if
<select resultType="com.bean.Users" parameterType="User" id="findByUser">
selectid,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
where id = #{id} and nickname=#{nickname} and realname=#{realname}</select>
模拟用户没有输全所有条件的情况,如传入的用户角色nickname参数为空,查询结果会出错。
在进行多条件查询的时候,用户并不一定会完整地输入所有的查询条件,对于类似情况,之前实例代码的SQL语句存在漏洞。
解决方案是使用动态SQL地if元素来实现多条件查询。
修改UserMapper.xml
<select resultType="com.bean.Users" parameterType="User" id="findByUser">
selectid,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
where
id = #{id}
<if test="nickname!=null"> <!--test属性表示进入if内需要的条件-->
and nickname=#{nickname}
</if>
<if test="realname!=null">
and realname=#{realname}
</if>
</select>
通过添加if元素就可以解决问题。
2.where
在上面修改后的查询语句的where子句含有一个固定条件
where
id = #{id}
当不需要用用户id查询时,修改查询语句
<select resultType="com.bean.Users" parameterType="User" id="findByUser">
selectid,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
where
<if test="nickname!=null"> <!--test属性表示进入if内需要的条件-->
nickname=#{nickname}
</if>
<if test="realname!=null">
and realname=#{realname}
</if>
</select>
当用户只输入的realname时,查询语句如下:
select
id,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
where
and realname=?
这时查询会报查询语句出错,多出个and。
同样当用户什么也没有输入时,查询语句如下
select
id,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
where
这时也会报查询语句出错,多出个where。
综上分析,若要解决此类问题需要智能地处理and和where,动态SQL中的where元素可以满足要求。
where元素主要是用来简化SQL语句中的where条件判断,并智能地处理and和or,不必担心多于关键字导致的语法错误。
<select resultType="com.bean.Users" parameterType="User" id="findByUser">
selectid,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
<where>
<if test="nickname!=null"> <!--test属性表示进入if内需要的条件-->
nickname=#{nickname}
</if>
<if test="realname!=null">
and realname=#{realname}
</if>
</where>
</select>
上述代码中,where元素标签会自动识别其标签内是否有返回值,若有,就插入一个where,此外,若该标签返回的内容是以and或or开头的,会自动剔除。
if+trim
在MyBatis中,除了使用if+where实现多条件查询,还有一个更为灵活的元素trim可以代替之前的做法。
trim元素也会自动识别其标签内是否有返回值,若有返回值,则在自己包含的内容前加上某些前缀,也可在其后加上某些后缀,与之对应的属性时prefix和suffix;
trim元素也可把包含内容首部的某些内容覆盖(即忽略),或者把尾部的某些内容覆盖,与之对应的属性是prefixOverrides和suffixOverrides;
正因为trim这样有强大的功能,我就可以利用trim来代替where元素,并实现与where元素相同的效果。
修改UserMapper.xml。
<select resultType="com.bean.Users" parameterType="User" id="findByUser">
selectid,nickname,realname,pwd,phone,email,address,create_time createTime,type,realid
from n_users
<trim prefix="where" prefixOverrides="or|and">
<if test="nickname!=null"> <!--test属性表示进入if内需要的条件-->
nickname=#{nickname}
</if>
<if test="realname!=null">
and realname=#{realname}
</if>
</trim>
</select>
属性 | 作用 |
---|---|
prefix | 通过自动识别是否有返回值后,在trim包含的内容上加上前缀 |
suffix | 通过自动识别是否有返回值后,在trim包含的内容上加上后缀 |
prefixOverrides | 对于trim包含内容的首部进行指定内容的忽略(如:and |or) |
suffixOverrides | 对于trim包含内容的尾部进行指定内容的忽略 |