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,使用映射 ...
随机推荐
- GCD介绍(二): 多核心的性能
GCD介绍(二): 多核心的性能 概念 为了在单一进程中充分发挥多核的优势,我们有必要使用多线程技术(我们没必要去提多进程,这玩意儿和GCD没关系).在低层,GCD全局dispatc ...
- C#获取本机IP搜集整理7种方法
今天打算试着写个小聊天程序,但是要用到获取本机IP,以前从没用过.摆渡百度了一会儿,出于贪心,想把各种获取本机IP的方法给找出来.摆渡+测试了几个小时,于是有了下面的成果,有点小累,但看到这些成果,也 ...
- Delphi动态创建组件,并释放内存
开发所用delphi版本是xe2,效果图如下: 代码如下: ---------------------------------------------------------------------- ...
- 解决js浮点数计算bug
1.加 function add(a, b) { var c, d, e; try { c = a.toString().split(".")[1].length; } catch ...
- javascript——迭代方法
<script type="text/javascript"> //五个迭代方法 都接受两个参数:要在每一项上运行的函数 和 运行该函数的作用域(可选) //every ...
- 使用BeanUtils组件
使用BeanUtils组件 前提 1:导入commons-beanutils-1.8.3.jar //根据 本人使用的是1.8.3的版本 2:导入日志包 //就是loggin ...
- PHPMailer发匿名邮件及Extension missing: openssl的解决
原文链接:http://www.tongfu.info/phpmailer%E5%8F%91%E5%8C%BF%E5%90%8D%E9%82 %AE%E4%BB%B6%E5%8F%8Aextensio ...
- 使用Thinkphp框架开发移动端接口
本文给大家分享的是使用thinkphp框架开发移动端接口的2种方法,一种是开发API,另外一种是实现移动端访问自动切换移动主题模板,从而实现伪app访问,下面我们就来详细看下如何实现吧. 方案一:给 ...
- mysql命令行导出导入数据库
一.MYSQL的命令行模式的设置: 桌面->我的电脑->属性->环境变量->新建->PATH=“:path\mysql\bin;”其中path为MYSQL的安装路径.二. ...
- 那些年被我坑过的Python——第十章Broker(rabbitMQ/redis)
基于RabbitMQ的direct任务驱动异步RPC程序实现: RPC_dispatcher指令分发器: #!/usr/bin/env python # -*- coding:utf-8 -*- __ ...