在MyBatis中提供了对SQL语句动态的组装能力,使用XML的几个简单元素,便能完成动态SQL的功能。大量的判断都可以在MyBatis的映射XML里面配置,以达到许多需要大量代码才能实现的功能,大大减少代码量,这体现了MyBatis的灵活、高度可配置性和可维护性。
在MyBatis中的动态SQL包括以下几个元素:if、choose(when,otherwise)、trim(where,set)、foreach。动态SQL实际使用的元素不多,但是它们带来了灵活性,减少工作量的同时,也在很大程度上提高了程序的可读性和可维护性。
1、if
if元素是最常用的判断语句,相当于java中的if语句,它常常与test元素联合使用。
if元素十分简单,下面我举一个简单的例子来说明如何使用它。场景描述:根据角色名称(roleName)去查找角色,如果角色名称不填写时,就不要用它作为条件查询。代码如下:
<select id="findRoles" parameterType="string" resultMap="roleResultMap">
select role_no,role_name,note from role where 1 = 1
<if test="roleName !=null and roleName !='' ">
and role_name like concat('%',#{roleName},'%')
</if>
<select>
2、choose、when、otherwise元素
choose元素就相当于java中的switch…case…case…语句,在映射器的动态语句中choose、when、otherwise这三个元素承担了这个功能。
我们继续来假设一个场景来说明:
- 如果角色编号(roleNo)不为空,则只用角色编号作为条件查询。
- 当角色编号为空,而角色名不为空时,则用角色名称作为条件进行模糊查询。
- 当角色编号和角色名都为空时,则要求角色备注不能为空。
代码如下:
<select id="findRoles" parameterType="role" resultMap="roleResultMap">
select role_no,role_name,note from role where 1 = 1
<choose>
<when test="roleNo != null and roleNo != '' ">
AND role_no=#{roleNo}
<when>
<when test="roleName != null and roleName != '' ">
AND role_name like concat('%',#{roleName},'%')
<when>
<otherwise>
AND note is not null
</otherwise>
</choose>
<select>
3、trim、where、set元素
trim元素是辅助元素,用于处理特定的SQL拼装问题。比如上一个例子中where后面有一个“1=1”,如果去掉的话会报出SQL的语法异常,但是当我们觉得加入“1=1”显得奇怪的时候,我们就可以用where元素去处理SQL以达到预期效果,代码如下:
<select id="findRoles" parameterType="role" resultMap="roleResultMap">
select role_no,role_name,note from role
<where>
<if test="roleName !=null and roleName !='' ">
and role_name like concat('%',#{roleName},'%')
</if>
<if test="note !=null and note !='' ">
and note like concat('%',#{note},'%')
</if>
</where>
<select>
当where元素里面的条件成立时,才会加入where这个SQL关键字到组装的SQL里面,否则就不加入。
有时候要去掉一些特殊的SQL的特殊语法,比如and、or。我们就可以使用trim元素也可以达到目标。
代码如下:
<select id="findRoles" parameterType="role" resultMap="roleResultMap">
select role_no,role_name,note from role
<trim prefix="where" prefixOverrides="and">
<if test="roleName !=null and roleName !='' ">
and role_name like concat('%',#{roleName},'%')
</if>
</trim>
<select>
trim元素意味着要去掉一些特殊的字符串,此时prefix代表的是语句的前缀,而prefixOverrides代表的是需要去掉哪种字符串。
set元素可以选择性的添加一个或多个字段来进行SQL操作。比如我们要更新某一对象的若干个字段,就可以用set元素实现。代码如下:
<update id="uodateRole" parameterType="role">
update role
<set>
<if test="roleName != null and roleName != '' ">
role_name = #{rolaName}
</if>
<if test="note !=null and note != '' ">
note =#{note}
</if>
</set>
where role_no = #{roleNo}
</update>
4、foreach元素
foreach元素是一个循环语句,它的作用是遍历集合,它能够很好地支持数组和List、Set接口的集合,对此提供遍历功能。它往往用于SQL中的in关键值。
在数据库中,经常需要根据编号找到相应的数据,比如角色。有一个List的角色编号的集合roleNoList,可以使用foreach元素找到在这个集合中的角色的详细信息。代码如下:
<select id="findUserBySex" resultType="user" >
select * from role where role_no in
<foreach item="roleNo" index="index" collection="roleNoList"
open="(" separator="," close=")" >
#{roleNo}
</foreach>
</select>
稍微解释一下:
- collection配置的roleNoList是传递进来的参数名称,它可以是一个数组、List、Set等集合。
- item配置的是循环中当前的元素。
- index配置的是当前元素在集合位置下表。
- open 和 close 配置的是以什么符号将这些集合元素包装起来。
- separtor是各元素的间隔符。
在SQL中常常用到in语句,但是对于大量数据的in语句要特别注意,因为他会消耗大量的性能。
5、bind元素
、bind元素的作用是通过OGNL表达式去自定义一个上下文变量,这样更方便使用。比如,要按角色名称进行模糊查询,可以使用bind元素把映射文件写成代码清单:
<select id="findRole" parameterType="string" result="com.learn.mybatis.bean.RoleBean" >
<bind name="pattern" value="'%'+_parameter+'%' "/>
select id,role_name as roleName,create_date as createDate,end_date as endDate,
end_flag as endFlag,note from role
where role_name like #{pattern}
</select>
bind还支持多个参数传递,首先先定义接口方法:
/**
*查询角色
*@param roleName 角色名称
*@param note 备注
*@return 符合条件的角色
*/
public List<RoleBean> findRole(@Param("roleName") String roleName ,@Param("note") String note);
定义映射文件和两个新的变量,然后执行模糊查询,代码如下:
<select id="findRole" resultType="com.learn.mybatis.bean.RoleBean">
<bind name="pattern_roleName" value=" '%'+roleName+'%' " />
<bind name="pattern_note" value=" '%'+note+'%' " />
select id,role_name as roleName,create_date as createDate,end_date as endDate,
end_flag as endFlag,note from role
where role_name like #{pattern_roleName} and note like #{pattern_note}
</select>