MyBatis(4):动态SQL
什么是动态SQL
MyBatis的一个强大特性之一通常是它的动态SQL能力。如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的省略逗号,动态SQL可以彻底处理这种痛苦。
通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中。
动态SQL元素和使用JSTL或其它相似的基于XML的文本处理器相似,在MyBatis之前的版本中,有很多元素需要了解,MyBatis3大大地提升了它们,现在用不到原先一半的元素就能工作了,MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。
OK,介绍就到这儿,下面来进入动态SQL的学习吧。
if
在动态SQL中所做的最通用的事情就是包含部分where子句的条件,比如:
|
1
2
3
4
5
6
|
<select id="selectInCondition" parameterType="student" resultType="student"> select * from student where studentId > #{studentId} <if test="studentName != null"> and studentName = #{studentName}; </if></select> |
具体实现不写了,那么如果我这么调用:
|
1
|
List<Student> list = StudentOperator.getInstance().selectInCondition(0, "Jack", 0, null); |
查询的就是studentId>0且studentName=”Jack”的所有学生信息,如果换一种调用方式:
|
1
|
List<Student> list = StudentOperator.getInstance().selectInCondition(0, null, 0, null); |
那么查询的就是studentId>0的所有学生信息。
多个where子句也是一样的,比如:
|
1
2
3
4
5
6
7
8
9
10
11
|
<select id="selectInCondition" parameterType="student" resultType="student"> <![CDATA[ select * from student where studentId > #{studentId} ]]> <if test="studentName != null and studentName != 'Jack' "> and studentName = #{studentName} </if> <if test="studentAge != 0"> and studentAge = #{studentAge}; </if></select> |
注意一下,能用”<![CDATA[ ... ]]>”尽量还是用,不过只包动态SQL外的内容。
另外,test里面可以判断字符串、整型、浮点型,大胆地写判断条件吧。如果属性是复合类型,则可以使用A.B的方式去获取复合类型中的属性来进行比较。
choose、when、otherwise
有时候我们不想应用所有的应用条件,相反我们想选择很多情况下的一种。和Java中的switch…case…类似,MyBasit提供choose元素。
上面的例子是两种if判断都可能存在,接下来使用choose、when、other做一些修改:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<select id="selectInCondition" parameterType="student" resultType="student"> <![CDATA[ select * from student where studentId > #{studentId} ]]> <choose> <when test="studentName != null"> and studentName = #{studentName}; </when> <when test="studentAge != 0"> and studentAge = #{studentAge}; </when> <otherwise> or 1 = 1; </otherwise> </choose></select> |
两个when只能满足一个,都不满足则走other。还是注意一下这里的”<![CDATA[ ... ]]>”,不可以包围整个语句。
trim、where、set
第一个例子已经示例了if的用法,但是这种用法有个缺陷—-动态SQL外必须有where子句。
什么意思,因为很多时候我们需要where后面的子句都动态生成,而不是事先有一个where,这样就有问题,比如说:
|
1
2
3
4
5
6
7
8
9
10
11
|
<select id="selectInCondition" parameterType="student" resultType="student"> <![CDATA[ select * from student where ]]> <if test="studentName != null and studentName != 'Jack' "> and studentName = #{studentName} </if> <if test="studentAge != 0"> and studentAge = #{studentAge}; </if></select> |
如果所有条件都不匹配,那么生成的SQL语句将是:
|
1
|
select * from student where |
这将导致查询失败。即使只满足一个查询条件还是有问题,比如满足studentName那个吧,生成的SQL语句将是:
|
1
|
select * from student where and studentName = #{studentName}; |
这个查询也会失败。
解决办法也有,一个讨巧的办法是用where 1 = 1的方式,即:
|
1
2
3
4
5
6
7
8
9
10
11
|
<select id="selectInCondition" parameterType="student" resultType="student"> <![CDATA[ select * from student where 1 = 1 ]]> <if test="studentName != null and studentName != 'Jack' "> and studentName = #{studentName} </if> <if test="studentAge != 0"> and studentAge = #{studentAge}; </if></select> |
因为”1 = 1″永远满足,所以相当于给where加了一层true而已,此时动态SQL生成什么where判断条件就是什么。
另外一个解决办法是利用MyBatis中的一个简单处理方式,这在90%情况下都会有用而且。而在不能使用的地方,可以以自定义方式处理。加上一个简单的改变,所有的事情都会顺利进行:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<select id="selectInCondition" parameterType="student" resultType="student"> <![CDATA[ select * from student ]]> <where> <if test="studentName != null and studentName != 'Jack' "> and studentName = #{studentName} </if> <if test="studentAge != 0"> and studentAge = #{studentAge}; </if> </where></select> |
where元素知道如果由被包含的标记返回任意内容,就仅仅插入where。而且,如果以”and”或”or”开头的内容,那么就会跳过where不插入。
如果where元素没有做出你想要的,那么可以使用trim元素来自定义。比如,和where元素相等的trim元素是:
|
1
2
3
|
<trim prefix="WHERE" prefixOverrides="AND |OR ">…</trim> |
即:
|
1
2
3
4
5
6
7
8
9
10
11
|
<select id="selectInCondition" parameterType="student" resultType="student"> select * from student <trim prefix="WHERE" prefixOverrides="AND |OR "> <if test="studentName != null and studentName != 'Jack' "> and studentName = #{studentName} </if> <if test="studentAge != 0"> and studentAge = #{studentAge}; </if> </trim></select> |
特别要注意,prefixOverrides中的空白也是很重要的。
最后一个小内容,和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包含不需要更新的。比如:
|
1
2
3
4
5
6
7
8
9
10
11
|
<update id="updateStudentAgeById" parameterType="Student"> <!--update student set studentAge = #{studentAge} where studentId = #{studentId}; --> <![CDATA[ update student ]]> <set> <if test="studentAge != 0">studentAge = #{studentAge}</if> </set> where studentId = #{studentId}</update> |
可以对比一下,注释掉的是原update语句,没有注释的是加入动态SQL之后的语句。
这里,set元素会动态前置set关键字,而且也会消除任意无关的逗号。如果你对和这里对等的trim元素好奇,它看起来是这样的:
|
1
2
3
|
<trim prefix="SET" prefixOverrides=",">…</trim> |
这种时候我们附加一个后缀,同时也附加一个前缀。
foreach
另外一个动态SQL通用的必要操作时迭代一个集合,通常是构建在in条件中的。比如(上面的例子都是我在自己电脑上跑通过的例子,这个例子就直接复制MyBatis官方文档上的内容了):
|
1
2
3
4
5
6
7
8
9
|
<select id="selectPostIn" resultType="domain.blog.Post"> <![CDATA[ SELECT * FROM POST P WHERE ID in ]]> <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach></select> |
foreach是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。他也允许你指定开放和关闭字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
MyBatis(4):动态SQL的更多相关文章
- MyBatis的动态SQL详解
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...
- Mybatis解析动态sql原理分析
前言 废话不多说,直接进入文章. 我们在使用mybatis的时候,会在xml中编写sql语句. 比如这段动态sql代码: <update id="update" parame ...
- mybatis 使用动态SQL
RoleMapper.java public interface RoleMapper { public void add(Role role); public void update(Role ro ...
- MyBatis框架——动态SQL、缓存机制、逆向工程
MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...
- 使用Mybatis实现动态SQL(一)
使用Mybatis实现动态SQL 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 写在前面: *本章节适合有Mybatis基础者观看* 前置讲解 我现在写一个查询全部的 ...
- MyBatis探究-----动态SQL详解
1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...
- mybatis中的.xml文件总结——mybatis的动态sql
resultMap resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功. 如果sql查询字段名和pojo的属性名不一致,可以通过re ...
- mybatis.5.动态SQL
1.动态SQL,解决关联sql字符串的问题,mybatis的动态sql基于OGNL表达式 if语句,在DeptMapper.xml增加如下语句; <select id="selectB ...
- MyBatis的动态SQL详解-各种标签使用
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...
- 利用MyBatis的动态SQL特性抽象统一SQL查询接口
1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...
随机推荐
- Objective-C中的分类与协议
分类 在谈分类之前,我们可以先探究下,OC中为什么出现分类这种机制,有什么好处? 假设你接到一个大项目:计算两个整数的和,差.接到任务的你马上动手.编写代码如下: #import <Founda ...
- C# 泛型2
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类 ...
- SpringMVC4+thymeleaf3的一个简单实例(篇二:springMVC与thymeleaf的整合)
延续前篇内容. 开始之前,我们首先要准备以下12个jar文件:spring-aop-4.3.3.RELEASE.jarspring-beans-4.3.3.RELEASE.jarspring-cont ...
- 命令模式(Command)
1.本质: 封装请求 2.定义: 把一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作 3.核心: 原本“行为请求者”和“行为执行者”是紧紧 ...
- request 报错The remote server returned an error: (415) Unsupported Media Type.
开发时遇到个问题,程序访问数据库数据,给服务器发送请求时,老是报错,返回的错误页面是: HTTP Status 415 - Unsupported Media Type type Status rep ...
- 基于Qt QGraphicsView的多点触摸绘图
本应用于基于QGraphicsView框架,实现多点触摸. 工程仅仅演示了多点触摸绘图,源自我前段时间一款基于Qt的绘图软件. 工程结构: kmp.h 定义了枚举 slide.h/cpp 定义了派生于 ...
- 每个Linux新手都应该记住的10个基本Linux命令
Linux对我们的生活有着很大的影响.至少,你的安卓手机上面就有Linux内核.然而,头一次入手Linux只会让你觉得不适.因为在Linux上,你通常应该使用终端命令,而不是只要点击启动器图像(就像你 ...
- Android扫描二维码 实现 登录网页
工程代码:ScanQRcode.zip ------------------------------------------------------------------ 1. 扫描二维码登录的实现 ...
- 转:PHP非阻塞模式
你可以任意转摘“PHP非阻塞模式”,但请保留本文出处和版权信息.作者:尘缘,QQ:130775,来源:http://www.4wei.cn/archives/1002336 让PHP不再阻塞当PHP作 ...
- [BZOJ 1085] [SCOI2005] 骑士精神 [ IDA* 搜索 ]
题目链接 : BZOJ 1085 题目分析 : 本题中可能的状态会有 (2^24) * 25 种状态,需要使用优秀的搜索方式和一些优化技巧. 我使用的是 IDA* 搜索,从小到大枚举步数,每次 DFS ...