Mybaits
动态sql
MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
动态传递参数有两种方式:
#{} 占位符
- 为参数占位符 ?,即sql 预编译
- 变量替换后,#{} 对应的变量自动加上单引号 ‘’
- 能防止sql 注入
// 1
select * from t_user where uid=#{uid}
// 2
select * from t_user where uid= ?
// 3
select * from t_user where uid= '1'
${} 占位符
只是简单的字符串替换
- ${} 为字符串替换,即 sql 拼接
- 变量替换后,${} 对应的变量不会加上单引号 ‘’
- 不能防止sql 注入
// 1 这里提前加上了'',
select * from t_user where uid= '${uid}'
// 2
select * from t_user where uid= '1'
// 3
select * from t_user where uid= '1'
- if
- choose when otherwise
- where
- set
- trim
- foreach
if
不支持 && 所以用 and or ||
条件 | 对应 |
---|---|
eq | == |
neq | != |
gt | > |
gte | >= |
lt | <(会报错)原因:不能包含< |
lte | <=(会报错)原因:不能包含< |
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = `ACTIVE`
<if test="title != null">
AND title like #{title}
</if>
</select>
// 判断是否为空
<if test="username != null and username != ''">
1 如果参数为数字类型的时候没有特俗需求的情况只需要判断是否为null即可。
<if test="id != null"></if>
2 如果为字符串类型
2.1 如果不需要过滤空串的情况 仅仅判断null即可
<if test="username != null"></if>
2.2 如果需要过滤空串,添加空串判断即可,不支持 && 所以这里用 and or || 来做逻辑与或的判断
<if test="username != null and '' != username"></if>
2.3 如果判断字符串是否已某个特俗字符开头,结尾等。直接调用String的对应方法即可
<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 username.lastIndexOf('ji') > 0"></if> <!-- 是否以什么结尾 -->
2.4 是否是某个特定字符串,某些业务有此需要。
<if test="username != null and 'hello' == username"></if>
<if test="username != null and 'hello' eq username"></if>
参数类型为非字符串类型的时候就需要写成
<if test="username != null and 'hello'.toString() == username.toString()"></if>
choose when otherwise
if标签是与(and)的关系,而 choose 是或(or)的关系
等价于
if(...){
....
}else if(...){
...
}else{
....
}
<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
where 元素知道只有在一个以上的if/when…条件有值的情况下才去插入"WHERE"子句。而且,若最后的内容是"AND"或"OR"开头的,where 元素也知道如何将他们去除。
出现的原因是为了解决一些垃圾问题
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
WHERE // 如果if没有匹配,那么sql语句会报错。
<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>
</select>
// 如果这些条件没有一个能匹配上将会怎样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
SELECT * FROM BLOG
WHERE
AND title like 'someTitle'
例子
<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>
<where>
<choose>
<when test="studentName!=null and studentName!='' ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%')
</when>
<when test="studentSex!= null and studentSex!= '' ">
AND ST.STUDENT_SEX = #{studentSex}
</when>
<when test="studentBirthday!=null">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday}
</when>
<when test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' ">
AND ST.CLASS_ID = #{classEntity.classID}
</when>
<otherwise>
</otherwise>
</choose>
</where>
也可以用trim替代
- prefixOverrides 属性会忽略通过管道分隔的文本序列(空格是必要的)
// prefixOverrides 属性会忽略通过管道分隔的文本序列(空格是必要的),而又一次附加了前缀中的值。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
set
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替代
// suffixOverrides忽略的是后缀中的值,而又一次附加了前缀中的值。
<trim prefix="SET" suffixOverrides=",">
...
</trim>
foreach
对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
属性 | 描述 |
---|---|
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对象没有默认的键。当然在作为入参时可以使用@Param(“keyName”)来设置键,设置keyName后,list,array将会失效。 |
-
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
- 如果传入的是单参数且参数类型是一个List(集合)的时候,collection属性值为list .
List<String> entitys; <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach>
- 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
int[] ids = new int[] {1,3,6,9}; <foreach item="item" index="index" collection="array" open="(" separator="," close=")"> #{item} </foreach>
- 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.
List ids = new ArrayList(); ids.add(1); ids.add(2); ids.add(3); ids.add(6); ids.add(7); ids.add(9); Map params = new HashMap(); params.put("ids", ids); params.put("title", "中国"); select * from t_blog where title like "%"#{title}"%" and id in <foreach item="item" index="index" collection="ids" open="(" separator="," close=")"> #{item} </foreach>
<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>
trim
去除或者添加特定的前缀或者后缀
属性 | 描述 |
---|---|
prefix | 给sql语句拼接的前缀 |
suffix | 给sql语句拼接的后缀 |
prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND" |
suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |
使用trim标签去除多余的and/or关键字
使用管道符时,管道符前面的空格必须带上。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
使用trim标签去除多余的逗号
<trim prefix="SET" suffixOverrides=",">
...
</trim>