什么是动态SQL

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

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

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

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

if

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

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. select * from student where studentId > #{studentId}
  3. <if test="studentName != null">
  4. and studentName = #{studentName};
  5. </if>
  6. </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. <select id="selectInCondition" parameterType="student" resultType="student">
  2. <![CDATA[
  3. select * from student where studentId > #{studentId}
  4. ]]>
  5. <if test="studentName != null and studentName != 'Jack' ">
  6. and studentName = #{studentName}
  7. </if>
  8. <if test="studentAge != 0">
  9. and studentAge = #{studentAge};
  10. </if>
  11. </select>

注意一下,能用"<![CDATA[ ... ]]>"尽量还是用,不过只包动态SQL外的内容。

另外,test里面可以判断字符串、整型、浮点型,大胆地写判断条件吧。如果属性是复合类型,则可以使用A.B的方式去获取复合类型中的属性来进行比较。

choose、when、otherwise

有时候我们不想应用所有的应用条件,相反我们想选择很多情况下的一种。和Java中的switch...case...类似,MyBasit提供choose元素。

上面的例子是两种if判断都可能存在,接下来使用choose、when、other做一些修改:

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. <![CDATA[
  3. select * from student where studentId > #{studentId}
  4. ]]>
  5. <choose>
  6. <when test="studentName != null">
  7. and studentName = #{studentName};
  8. </when>
  9. <when test="studentAge != 0">
  10. and studentAge = #{studentAge};
  11. </when>
  12. <otherwise>
  13. or 1 = 1;
  14. </otherwise>
  15. </choose>
  16. </select>

两个when只能满足一个,都不满足则走other。还是注意一下这里的"<![CDATA[ ... ]]>",不可以包围整个语句。

trim、where、set

第一个例子已经示例了if的用法,但是这种用法有个缺陷----动态SQL外必须有where子句。

什么意思,因为很多时候我们需要where后面的子句都动态生成,而不是事先有一个where,这样就有问题,比如说:

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. <![CDATA[
  3. select * from student where
  4. ]]>
  5. <if test="studentName != null and studentName != 'Jack' ">
  6. and studentName = #{studentName}
  7. </if>
  8. <if test="studentAge != 0">
  9. and studentAge = #{studentAge};
  10. </if>
  11. </select>

如果所有条件都不匹配,那么生成的SQL语句将是:

  1. select * from student where

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

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

这个查询也会失败。

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

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. <![CDATA[
  3. select * from student where 1 = 1
  4. ]]>
  5. <if test="studentName != null and studentName != 'Jack' ">
  6. and studentName = #{studentName}
  7. </if>
  8. <if test="studentAge != 0">
  9. and studentAge = #{studentAge};
  10. </if>
  11. </select>

因为"1 = 1"永远满足,所以相当于给where加了一层true而已,此时动态SQL生成什么where判断条件就是什么。

另外一个解决办法是利用MyBatis中的一个简单处理方式,这在90%情况下都会有用而且。而在不能使用的地方,可以以自定义方式处理。加上一个简单的改变,所有的事情都会顺利进行:

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. <![CDATA[
  3. select * from student
  4. ]]>
  5. <where>
  6. <if test="studentName != null and studentName != 'Jack' ">
  7. and studentName = #{studentName}
  8. </if>
  9. <if test="studentAge != 0">
  10. and studentAge = #{studentAge};
  11. </if>
  12. </where>
  13. </select>

where元素知道如果由被包含的标记返回任意内容,就仅仅插入where。而且,如果以"and"或"or"开头的内容,那么就会跳过where不插入。

如果where元素没有做出你想要的,那么可以使用trim元素来自定义。比如,和where元素相等的trim元素是:

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

  2. </trim>

即:

  1. <select id="selectInCondition" parameterType="student" resultType="student">
  2. select * from student
  3. <trim prefix="WHERE" prefixOverrides="AND |OR ">
  4. <if test="studentName != null and studentName != 'Jack' ">
  5. and studentName = #{studentName}
  6. </if>
  7. <if test="studentAge != 0">
  8. and studentAge = #{studentAge};
  9. </if>
  10. </trim>
  11. </select>

特别要注意,prefixOverrides中的空白也是很重要的

最后一个小内容,和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包含不需要更新的。比如:

  1. <update id="updateStudentAgeById" parameterType="Student">
  2. <!--update student set studentAge = #{studentAge} where
  3. studentId = #{studentId}; -->
  4. <![CDATA[
  5. update student
  6. ]]>
  7. <set>
  8. <if test="studentAge != 0">studentAge = #{studentAge}</if>
  9. </set>
  10. where studentId = #{studentId}
  11. </update>

可以对比一下,注释掉的是原update语句,没有注释的是加入动态SQL之后的语句。

这里,set元素会动态前置set关键字,而且也会消除任意无关的逗号。如果你对和这里对等的trim元素好奇,它看起来是这样的:

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

  2. </trim>

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

foreach

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

  1. <select id="selectPostIn" resultType="domain.blog.Post">
  2. <![CDATA[
  3. SELECT * FROM POST P WHERE ID in
  4. ]]>
  5. <foreach item="item" index="index" collection="list"
  6. open="(" separator="," close=")">
  7. #{item}
  8. </foreach>
  9. </select>

foreach是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。他也允许你指定开放和关闭字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。

MyBatis4:动态SQL的更多相关文章

  1. 值得注意的ibatis动态sql语法格式

    一.Ibatis常用动态sql语法,简单粗暴用一例子 <select id="iBatisSelectList" parameterClass="java.util ...

  2. Mysql - 游标/动态sql/事务

    游标这个在我目前的项目里面用的还不多, 但是其功能还是很强大的. 动态sql以前都没用过, 是跟着富士康(不是张全蛋的富土康哦)过来的同事学的. 还是挺好用的. 我的数据库方面, 跟他学了不少. 在此 ...

  3. 分享公司DAO层动态SQL的一些封装

    主题 公司在DAO层使用的框架是Spring Data JPA,这个框架很好用,基本不需要自己写SQL或者HQL就能完成大部分事情,但是偶尔有一些复杂的查询还是需要自己手写原生的Native SQL或 ...

  4. MySQL存储过程动态SQL语句的生成

    用Mysql存储过程来完成动态SQL语句,使用存储过程有很好的执行效率: 现在有要求如下:根据输入的年份.国家.节假日类型查询一个节假日,我们可以使用一般的SQL语句嵌入到Java代码中,但是执行效率 ...

  5. 【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】

    一.动态SQL 什么是动态SQL,就是在不同的条件下,sql语句不相同的意思,曾经在“酒店会员管理系统”中写过大量的多条件查询,那是在SSH的环境中,所以只能在代码中进行判断,以下是其中一个多条件查询 ...

  6. 自定义函数执行动态sql语句

    --函数中不能调用动态SQL,使用用存储过程吧.如果还要对函数做其他操作,换成存储过程不方便,可以考虑把其他操作一起封装在存储过程里面.如:   create proc [dbo].[FUN_YSCL ...

  7. mybatis入门基础(五)----动态SQL

    一:动态SQL 1.1.定义 mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.2.案例需求 用户信息综合查询列表这个statement的定义使用动态s ...

  8. mybatis 动态sql表达式相关应用

    一.mybatis 表达式简介 对于mybatis3 ,提供了一种动态sql的方式.通过动态sql我们可以直接在mybatis 的xm映射文件中直接通过条件判断的方式进行查询添加的拼接.mybatis ...

  9. (转)Mybatis高级映射、动态SQL及获得自增主键

    原文:http://www.cnblogs.com/edwinchen/p/4105278.html?utm_source=tuicool&utm_medium=referral 一.动态SQ ...

随机推荐

  1. ASP.NET Core 1.1 简介

    ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...

  2. OpenCASCADE Expression Interpreter by Flex & Bison

    OpenCASCADE Expression Interpreter by Flex & Bison eryar@163.com Abstract. OpenCASCADE provide d ...

  3. kafka源码分析之一server启动分析

    0. 关键概念 关键概念 Concepts Function Topic 用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上. Partition 是Kafka中横向扩展和一 ...

  4. DOM的小练习,两个表格之间数据的移动

    本次讲的是两个表格之间数据的移动,左边的表格移动到右边,并且左边表格移动内容消失. <head>   <meta http-equiv="Content-Type" ...

  5. 使用po模式读取豆瓣读书最受关注的书籍,取出标题、评分、评论、题材 按评分从小到大排序并输出到txt文件中

    #coding=utf-8from time import sleepimport unittestfrom selenium import webdriverfrom selenium.webdri ...

  6. BPM流程中心解决方案分享

    一.需求分析 在过去办公自动化的浪潮中,很多企业已经实施了OA流程,但随着客户的发展和对流程管理的越来越重视, 客户对流程应用需求越来越深 入,您可能面临以下需求: 1.流程功能不能满足需求,包括流程 ...

  7. Oracle创建表空间

    1.创建表空间 导出Oracle数据的指令:/orcl file=C:\jds.dmp owner=jds 导入Oracle数据的指令:imp zcl:/orcl file=C:\jds.dmp fu ...

  8. 创建maven项目(cmd 命令)

    2016五月 22 原 创建maven项目(cmd 命令) 分类:maven (994) (0) 1.普通方式创建 1)进入cmd窗口执行 mvn archetype:generate 2) 光标停止 ...

  9. 性能测试工具 wrk 安装与使用

    介绍 今天给大家介绍一款开源的性能测试工具 wrk,简单易用,没有Load Runner那么复杂,他和 apache benchmark(ab)同属于性能测试工具,但是比 ab 功能更加强大,并且可以 ...

  10. [PHP源码阅读]strtolower和strtoupper函数

    字符串的操作函数中,字符串的大小写转换也算是比较常用的函数,其底层实现也比较简单,下面来一探究竟. 我在github上有对PHP源码更详细的注解.感兴趣的可以围观一下,给个star.PHP5.4源码注 ...