本章节主要介绍mybatis的动态sql的作用和用法
一、mybatis动态SQL概述
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
二、mybatis动态SQL标签
标签 | 作用 | 备注 |
if | 判断语句 | 单条件分支判断 |
choose(when、otherwise) | 相当于java中带return的switch和catch语句 | 多条件分之判断 |
trim(where、set) | 辅助元素,用于处理特定的sql拼装问题,比如去除多余的and、or、, 等 | 用于处理sql拼装问题 |
foeach | 循环语句 | 在in语句等列举条件常用 |
动态sql实际使用的标签并不多,但是却可以带来极大的灵活性,很大程度上提高的程序的可读性和可维护性。
1、if标签
if标签会对test中的表达式做判断,如果表达式成立就执行if标签中的sql语句,如果不成立就不执行。
test中的表达式采用OGNL表达式的方式,可以对参数取值判断
<!--
if test:判断表达式(OGNL)从参数中取值进行判断
如果表达式中包含&& "" 等需要进行特殊字符的转义
-->
<select id="getEmpIf" resultMap="employee">
SELECT id,last_name,email,gender
FROM tbl_employee
WHERE 1=1
<if test="lastName != null">
AND last_Name = #{lastName}
</if>
<if test="department != null and department.id != null">
AND dept_id = #{department.id}
</if>
</select>
2、choose(when、otherwise)标签
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句
<select id="getEmpsByConditionChoose" resultType="com.wcg.mybatis.entity.Employee">
select * from tbl_employee
<where>
<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null">
last_name like #{lastName}
</when>
<when test="email!=null">
email = #{email}
</when>
<otherwise>
gender = 0
</otherwise>
</choose>
</where>
</select>
3、trim、where、set标签
如果在where条件中只使用if标签可能会导致一些SQL语法错误(并没有像上面讲述的if标签时,加入条件1=1):
<select id="getEmpIf" resultMap="employee">
SELECT id,last_name,email,gender
FROM tbl_employee
WHERE
<if test="lastName != null">
AND last_Name = #{lastName}
</if>
<if test="department != null and department.id != null">
AND dept_id = #{department.id}
</if>
</select>
如果上面这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:
SELECT id,last_name,email,gender
FROM tbl_employee WHERE
如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样: :
SELECT id,last_name,email,gender
FROM tbl_employee
WHERE AND dept_id = #{department.id}
where标签
这时候就可以使用where标签:where 标签只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
<select id="getEmpsByConditionWhere" resultMap="employee">
SELECT * FROM BLOG
<where>
<if test="lastName != null">
AND last_Name = #{lastName}
</if>
<if test="department != null and department.id != null">
AND dept_id = #{department.id}
</if>
</where>
</select>
set标签
set 标签会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(注意:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)
<update id="updateEmp">
<!-- Set标签的使用 -->
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
</update>
trim标签
在上面讲述的where标签和set标签中,都是可以使用trim标签替代而且功能更强大
例如:后面多出的and或者or where标签不能解决
属性 | 作用 |
prefix | 前缀: prefix给拼串后的整个字符串加一个前缀 |
prefixOverrides | 前缀覆盖: 去掉整个字符串前面多余的字符 |
suffix | 后缀 :suffix给拼串后的整个字符串加一个后缀 |
suffixOverrides | 后缀覆盖: 去掉整个字符串后面多余的字符 |
使用trim替代where:
<select id="getEmpsByConditionTrim" resultMap="employee">
select id,last_name,email,gender from tbl_employee
<!-- 自定义字符串的截取规则 -->
<trim prefix="where" suffixOverrides="AND">
<if test="lastName != null">
AND last_Name = #{lastName}
</if>
<if test="department != null and department.id != null">
AND dept_id = #{department.id}
</if>
</trim>
</select>
使用trim替代set:
<update id="updateEmp">
<!-- Set标签的使用 -->
update tbl_employee
<trim prefix="set" suffixOverrides=",">
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id=#{id}
</update>
4.foreach标签
foreach元素是一个循环语句,它的作用是遍历集合,它能够很好地对数组和list、set接口的集合提供遍历的功能
属性 | 作用 |
collection | 指定需要遍历的集合 |
item | 将当前遍历出的元素赋值给指定的变量 |
separator | 每个元素的分隔符 |
open | 遍历出所有结果拼接的开始字符 |
close | 遍历出所有结果拼接的结束字符 |
index | 索引:遍历list的时候是index就是索引,item就是当前值 遍历map的时候index表示的就是map的key,item就是map的值 |
<select id="getEmpsByConditionForeach" resultMap="employee">
select * from tbl_employee
<!--
#{变量名}就能取出变量的值也就是当前遍历出的元素
-->
<foreach collection="ids" item="item_id" separator=","
open="where id in(" close=")">
#{item_id}
</foreach>
</select>
三、额外说明
除了上述的一些动态标签,映射器中海油一些其它的标签:
1、bind标签
bind标签的作用是通过OGNL表达式去定义一个上下文变量,方便使用时去引用。比如在使用模糊查询的时候,使用#{}进行预编译处理,则必须在传参的时候就带上%或者_来进行模糊查询,因为如果在sql语句中拼接会报错。这时候就可以使用bind来解决
<select id="getEmpsTestInnerParameter" resultMap="employee">
<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
<bind name="_lastName" value="'%'+lastName+'%'"/>
select * from tbl_employee
<if test="_parameter!=null">
where last_name like #{lastName}
</if>
</select>
2、sql标签
sql标签的作用是可以定义一条sql的一部分,在使用的时候可以进行引用,常用的方式是定义列名。在编写select、insert等语句的经常要反复的编写列名,这时候就可以直接进行引用
注:
1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
2、include来引用已经抽取的sql:
3、include还可以自定义一些property,sql标签内部就能使用自定义的属性
include-property:取值的正确方式${prop},
#{不能使用这种方式}
<sql id="employeeColumn">
id,last_name,email,gender
</sql>
<select id="getAllEmp" resultMap="employee">
SELECT
<include refid="employeeColumn"></include>
FROM tbl_employee
</select>
3、映射器中的两个内置参数
mybatis默认还有两个内置参数:
- _parameter: 代表整个参数
单个参数:_parameter就是这个参数
多个参数:参数会被封装为一个map;_parameter就是代表这个map
- _databaseId:如果配置了databaseIdProvider标签。
_databaseId就是代表当前数据库的别名mysql