动态SQL
开发人员在使用JDBC或其他类似的框架进行数据库开发时,通常都要根据需求去手动拼装SQL,这是一个非常麻烦且痛苦的工作,
而MyBatis提供的对SQL语句动态组装的功能,恰能很好的解决这一麻烦工作。
动态SQL是MyBatis的强大特性之一,MyBatis3采用了功能强大的基于OGNL的表达式来完成动态SQ
<if>元素
在MyBatis中,<if>元素是最常用的判断语句,它类似于Java中的if语句,主要用于实现某些简单的条件选择。其基本使用示例如下:
<!--使用<if>元素对username和jobs进行非空判断,并动态组装SQL-->
select * from t_customer where 1=1
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
<choose>、<when>、<otherwise>元素
在MyBatis如果条件过多,这时就不适合使用If,这种情况显然更适合使用switch…case…default语句来处理,而在SQL中就可以使用<choose>、<when>、<otherwise>元素组合进行处理。其基本使用示例如代码所示:
<!--使用<choose>及其子元素依次对条件进行非空判断,并动态组装SQL-->
select * from t_customer where 1=1
<choose>
<when test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</when>
<when test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
<where>、<trim>元素
针对“where 1=1”,在MyBatis的SQL中就可以使用<where>或<trim>元素进行动态处理。
<where>元素处理
<where>会自动判断SQL语句,只有<where>内的条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;还会去除多余的“AND”或“OR”。
<trim>元素处理
<trim>的作用是去除特殊的字符串,它的prefix属性代表语句的前缀,prefixOverrides属性代表需要去除的哪些特殊字符串,功能和<where>基本是等效的。
select * from t_customer
<where>
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</where>
select * from t_customer
<trim prefix="where" prefixOverrides="and">
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</trim>
<set>元素
动态更新某个对象的指定字段
<!--使用<set>和<if>元素对username和jobs进行更新判断,并动态组装SQL。这样就只需要传入想要更新的字段即可-->
<update id="updateCustomer" parameterType="com.po.Customer">
update t_customer
<set>
<if test="username !=null and username !=''">
username=#{username},
</if>
<if test="jobs !=null and jobs !=''">
jobs=#{jobs},
</if>
</set>
where id=#{id}
</update>
<foreach>元素
在面对数量比较大的查询时,挑选指定条件的数据
<select id="findCustomerByIds" parameterType="List"
resultType="com.po.Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="list"
open="(" separator="," close=")">
#{id}
</foreach>
</select>
<foreach>元素中使用的几种属性的描述具体如下
index:配置的是当前元素在集合的位置下标。
collection:配置的list是传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名等。
open和close:配置的是以什么符号将这些集合元素包装起来。
separator:配置的是各个元素的间隔符。
在使用<foreach>时最关键也是最容易出错的就是collection属性,该属性是必须指定的,而且在不同情况下,该属性的值是不一样的。主要有以下3种情况:
如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection)。
如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。
如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。
<bind>元素
在处理模糊查询时,最初使用的是 select * from t_customer where username like '%${value}%'
但是这样做的缺点如下:
如果使用“${}”进行字符串拼接,则无法防止SQL注入问题;
如果改用concat函数进行拼接,则只针对MySQL数据库有效;
如果改用“||”进行字符串拼接,则只针对Oracle数据库有效。
这样,映射文件中的SQL就要根据不同的情况提供不同形式的实现,这显然是比较麻烦的,且不利于项目的移植。
为了减少这种麻烦,就可以使用MyBatis的<bind>元素来解决这一问题。
<select id="findCustomerByName" parameterType="com.po.Customer" resultType="com.po.Customer">
<!--_parameter.getUsername()表示传递进来的参数(也可以直接写成对应的参数变量名,如username)-->
<bind name="pattern_username" value="'%'+_parameter.getUsername()+'%'" />
select * from t_customer
where
<!--需要的地方直接引用<bind>元素的name属性值即可-->
username like #{pattern_username}
</select>