转载:http://www.cnblogs.com/xrq730/p/5289638.html

什么是动态SQL

MyBatis的一个强大特性之一通常是它的动态SQL能力。如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的省略逗号,动态SQL可以彻底处理这种痛苦。

通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中。

动态SQL元素和使用JSTL或其它相似的基于XML的文本处理器相似,在MyBatis之前的版本中,有很多元素需要了解,MyBatis3大大地提升了它们,现在用不到原先一半的元素就能工作了,MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。

OK,介绍就到这儿,下面来进入动态SQL的学习吧。

if

在动态SQL中所做的最通用的事情就是包含部分where子句的条件,比如:

<select id="selectInCondition" parameterType="student" resultType="student">
select * from student where studentId > #{studentId}
<if test="studentName != null">
and studentName = #{studentName};
</if>
</select>

具体实现不写了,那么如果我这么调用:

List<Student> list = StudentOperator.getInstance().selectInCondition(0, "Jack", 0, null);

查询的就是studentId>0且studentName="Jack"的所有学生信息,如果换一种调用方式:

List<Student> list = StudentOperator.getInstance().selectInCondition(0, null, 0, null);

那么查询的就是studentId>0的所有学生信息。

多个where子句也是一样的,比如:

<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做一些修改:

<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,这样就有问题,比如说:

<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语句将是:

select * from student where

这将导致查询失败。即使只满足一个查询条件还是有问题,比如满足studentName那个吧,生成的SQL语句将是:

select * from student where and studentName = #{studentName};

这个查询也会失败。

解决办法也有,一个讨巧的办法是用where 1 = 1的方式,即:

<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%情况下都会有用而且。而在不能使用的地方,可以以自定义方式处理。加上一个简单的改变,所有的事情都会顺利进行:

<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元素是:

<trim prefix="WHERE" prefixOverrides="AND |OR ">

</trim>

即:

<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元素可以被用于动态包含更新的列,而不包含不需要更新的。比如:

<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元素好奇,它看起来是这样的:

<trim prefix="SET" prefixOverrides=",">

</trim>

这种时候我们附加一个后缀,同时也附加一个前缀。

foreach

另外一个动态SQL通用的必要操作时迭代一个集合,通常是构建在in条件中的。比如(上面的例子都是我在自己电脑上跑通过的例子,这个例子就直接复制MyBatis官方文档上的内容了):

<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的更多相关文章

  1. 【分享】标准springMVC+mybatis项目maven搭建最精简教程

    文章由来:公司有个实习同学需要做毕业设计,不会搭建环境,我就代劳了,顺便分享给刚入门的小伙伴,我是自学的JAVA,所以我懂的.... (大图直接观看显示很模糊,请在图片上点击右键然后在新窗口打开看) ...

  2. Java MyBatis 插入数据库返回主键

    最近在搞一个电商系统中由于业务需求,需要在插入一条产品信息后返回产品Id,刚开始遇到一些坑,这里做下笔记,以防今后忘记. 类似下面这段代码一样获取插入后的主键 User user = new User ...

  3. [原创]mybatis中整合ehcache缓存框架的使用

    mybatis整合ehcache缓存框架的使用 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓 ...

  4. 【SSM框架】Spring + Springmvc + Mybatis 基本框架搭建集成教程

    本文将讲解SSM框架的基本搭建集成,并有一个简单demo案例 说明:1.本文暂未使用maven集成,jar包需要手动导入. 2.本文为基础教程,大神切勿见笑. 3.如果对您学习有帮助,欢迎各种转载,注 ...

  5. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  6. MyBatis基础入门--知识点总结

    对原生态jdbc程序的问题总结 下面是一个传统的jdbc连接oracle数据库的标准代码: public static void main(String[] args) throws Exceptio ...

  7. Mybatis XML配置

    Mybatis常用带有禁用缓存的XML配置 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE ...

  8. MyBatis源码分析(一)开篇

    源码学习的好处不用多说,Mybatis源码量少.逻辑简单,将写个系列文章来学习. SqlSession Mybatis的使用入口位于org.apache.ibatis.session包中的SqlSes ...

  9. (整理)MyBatis入门教程(一)

    本文转载: http://www.cnblogs.com/hellokitty1/p/5216025.html#3591383 本人文笔不行,根据上面博客内容引导,自己整理了一些东西 首先给大家推荐几 ...

  10. MyBatis6:MyBatis集成Spring事物管理(下篇)

    前言 前一篇文章<MyBatis5:MyBatis集成Spring事物管理(上篇)>复习了MyBatis的基本使用以及使用Spring管理MyBatis的事物的做法,本文的目的是在这个的基 ...

随机推荐

  1. bzoj1698 / P1606 [USACO07FEB]白银莲花池Lilypad Pond

    P1606 [USACO07FEB]白银莲花池Lilypad Pond 转化为最短路求解 放置莲花的方法如果直接算会有重复情况. 于是我们可以先预处理和已有莲花之间直接互相可达的点,将它们连边(对,忽 ...

  2. centos下gitlab私服完整安装部署(nginx+MySQL+redis+gitlab-ce+gitlab-shell+)

    系统环境cat /etc/redhat-release CentOS release 6.8 (Final) nginx -vnginx version: nginx/1.9.15 redis-cli ...

  3. mamcached+magent构建memcached集群

    cat /etc/redhat-release CentOS release 6.7 (Final) 防火墙.selinux 关闭 192.168.12.30 安装libevent和memcached ...

  4. 20145101《Java程序设计》第6周学习总结

    20145101<Java程序设计>第6周学习总结 教材学习内容总结 第十章输入和输出 java.io.InputStream.java.io.OutputStream实例分别作为输入.输 ...

  5. Android 手机小闹钟

    Android 手机小闹钟 一.这一篇主要使用系统为我们提供的一个服务AlarmManager来制作一个Android小闹钟,同时还涉及到了自定义主题.判断第一次启动应用.自定义动画.对话框.制作关闭 ...

  6. 20145204《网络对抗》逆向及bof基础实践

    20145204<网络对抗>逆向及bof基础实践 实践目的说明 实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何 ...

  7. java.lang.NoClassDefFoundError错误

    根据前文,很明显NoClassDefFoundError的错误是因为在运行时类加载器在classpath下找不到需要加载的类,所以我们需要把对应的类加载到classpath中,或者检查为什么类在cla ...

  8. java的Date() 转换符

    本字段下均转自 csdn 阿念1989 本文是学习网络上的文章时的总结,感谢大家无私的分享. System.out.printf()方法可以对日期做处理输出. 对应列表 转换符 类型 举例 c 完整的 ...

  9. shell 杀掉指定进程的服务

    check_results=`ps -ef|grep bp_driver.launch|awk '{print $2}'|sed -n 1p` echo `kill - $check_results` ...

  10. NIO 之 ByteBuffer

    前言 对于刚接触ByteBuffer人来说,想要完全理解会稍微有点困难,正巧前几天有人问我,想到好久没写文章,就整理一下. 概念理解 对于ByteBuffer的一些概念不理解的情况下,如果直接打开源码 ...