mybatis的强大特性之一便是它的动态sql。使用过JDBC或其他类似框架的人都会知道,根据不同条件拼接SQL语句时不仅不能忘了必要的空格,还要注意省略掉列名列表最后的逗号,处理方式麻烦且凌乱。mybaits的动态SQL则能让我们摆脱这种痛苦。
以下是mybatis的动态SQL在xml中支持的几种标签。
if
choose(when,otherwise)
trim(where,set)
foreach
bind
1、if用法
<if test=""> </if>
2、choose用法
if标签提供了基本的条件判断,但是它无法实现if...else if ....else....的逻辑,要想实现这样的逻辑,就需要用到choose when otherwise。choose元素中包含when和otherwise两个标签,一个choose中至少有一个when,有0个或者1个otherwise.
select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user where 1 = 1 <choose> <when test="id != null"> and id = #{id} </when> <when test="userName != null and userName != ''"> and user_name = #{userName} </when> <otherwise> limit 0 </otherwise> </choose>
3、where、set、trim用法
这3个标签解决了类似的问题,并且where和set都属于trim的一种具体用法。
3.1 where用法
如果该标签包含的元素中有返回值,就插入一个where;如果where后面的字符串是以AND和or开头的,就将他们剔除。
select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user <where> <if test="userName != null and userName != ''"> <bind name="userNameLike" value=" '%' +userName+'%' "/> and user_name like #{userNameLike} </if> <if test="userEmail != '' and userEmail != null"> and user_email = #{userEmail} </if> </where>
3.2 set用法
如果该标签包含的元素中有返回值,就插入一个set;如果set后面的字符串是以逗号结尾的,就将这个逗号剔除。
update sys_user <set> <if test="userName != null and userName != ''"> user_name = #{userName}, </if> <if test="userPassword != null and userPassword != ''"> user_password = #{userPassword}, </if> <if test="userEmail != null and userEmail != ''"> user_email = #{userEmail}, </if> <if test="userInfo != null and userInfo != ''"> user_info = #{userInfo}, </if> <if test="headImg != null"> head_img = #{headImg, jdbcType=BLOB}, </if> <if test="createTime != null"> create_time = #{createTime, jdbcType=TIMESTAMP}, </if> id = #{id}, </set> where id = #{id}
3.3 trim用法
where和set标签的功能都可以用trim标签来实现,并且在底层就是通过trimSqlNode实现的。
where标签对应trim的实现如下。
<trim prefix="where" prefixOverrides="and | or"> ....</trim>
set标签对应的trim实现如下。
<trim prefix="set" suffixOverrides=","> .... </trim>
trim标签有如下属性。
prefix:当trim元素内包含内容时,会给内容增加prefix指定的前缀。
prefixOverrides:当trim元素内包含内容时,会把内容中匹配的前缀字符串去掉。
suffix:当trim元素内包含内容时,会给内容增加suffix指定的后缀。
suffixOverrides:当trim元素内包含内容时,会把内容中匹配的后缀字符串去掉。
4、foreach用法
SQL语句中有时会使用IN关键字,例如id in(1、2、 3).可以使用$(ids)方式直接获取值,但这种写法不能防止SQL注入,想避免SQL注入就需要用#{}的方式,这时就要配合使用foreach标签来满足需求。
foreach可以对数组、map或实现了Iterable接口(如List、set)的对象进行遍历。数组在处理时会转换为List对象,因此foreach遍历的对象可以分为两大类:Iterable类型和Map类型。这两种类型的遍历循环时情况不一样。
foreach包含以下属性。
collection:必填,值为要迭代循环的属性名。这个属性值的情况有很多。
item:变量名,值为从迭代对象中取出的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代循环的对象是Map类型时,这个值为Map的key。
open:整个循环内容开头的字符串。
close:整个循环内容结尾的字符串。
separator:每次循环的分隔符。
4.1foreach实现in集合
select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user where id in <foreach collection="list" open="(" close=")" separator="," item="id" index="i"> #{id} </foreach>
参数是Map类型
使用Map和使用@Param注解方式类似,将collection指定为对应map中的key即可。如果要循环所传入的Map,推荐使用@Param注解指定名字,此时可将collection设置为指定的名字,如果不想指定名字,就使用默认值_parameter
update sys_user set <foreach collection="_parameter" item="val" index="key" separator=","> ${key} = #{val} </foreach> where id = #{id}
5、bind 用法
bind标签可以使用OGNL表达式创建一个变量并将其绑定到上下文中。
例:
<if test="userName != null and userName != ''"> <bind name="userNameLike" value=" '%' +userName+'%' "/> and user_name like #{userNameLike} </if>
bind标签的两个属性都是必选项,name为绑定到上下文的变量名,value为OGNL表达式。创建一个bind标签的变量后,就可以在下面直接使用,使用bind拼接字符串不仅可以避免因更换数据库而修改SQL,也能预防SQL注入。