MyBatis4:动态SQL

什么是动态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">
    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[ ... ]]>"了。

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

choose、when、otherwise

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

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

<select id="selectInCondition" parameterType="student" resultType="student">
    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[ ... ]]>",动态SQL都一样。

trim、where、set

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

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

<select id="selectInCondition" parameterType="student" resultType="student">
    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">
    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">
    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}; -->
    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">
  SELECT * FROM POST P WHERE ID in
  <foreach item="item" index="index" collection="list"
    open="(" separator="," close=")">
    #{item}
  </foreach>
</select>

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

时间: 2024-10-22 10:07:43

MyBatis4:动态SQL的相关文章

MyBatis动态SQL小结

p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; font-size: 10.5pt; font-family: 等线 } .MsoChpDefault { font-family: 等线 } div.WordSection1 { } ol { margin-bottom: 0cm } ul { margin-bottom: 0cm } Mybati

笔记:MyBatis 动态SQL

有时候,静态的SQL语句并不能满足应用程序的需求.我们可以根据一些条件,来动态地构建SQL语句.例如,在Web应用程序中,有可能有一些搜索界面,需要输入一个或多个选项,然后根据这些已选择的条件去执行检索操作.在实现这种类型的搜索功能,我们可能需要根据这些条件来构建动态的SQL语句.如果用户提供了任何输入条件,我们需要将那个条件 添加到SQL语句的WHERE子句中. MyBatis通过使用<if>,<choose>,<where>,<foreach>,<

MyBatis 动态sql详解

MyBatis的动态sql语句 1.if 条件 2.choose , when 和 otherwise条件 3.where 条件 where条件:1.自动加上where.2.如果where子句以and或者or开头,则自动删除第一个and或者or..所以我们不需要自己加where 4.trim 条件 trim条件和where条件类似但是功能更强大:不仅可以替换掉子句开头的and或者or,还提供了加前缀和后缀的功能. 5.forEach循环 6.set 条件 set条件:自动加上set,自动去除最后

db2存储过程动态sql被截断

编写存储过程,使用动态sql时,调试时发现变量赋值后被截断. 关键代码如下: 实现的效果是先把上下游做对比的sql语句和相关参数存入RKDM_DATA_VOID_RULE, 执行存储过程后把两个sql语句得出的结果插入另一张结果表RKDM_DATA_VOID_CHK_REST. 建表语句: CREATE TABLE RKDM_DATA_VOID_CHK_REST ( DATA_DT DATE, ORDR_NUM INTEGER, CHK_BIG_CLS VARCHAR(256), DATA_PR

mybatis入门-动态sql

什么是动态sql 判断的动态sql mybatis核心就是对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 现有需求如下:需要查询用户,输入的是用户类,如果用户的性别类不为空,则将性别作为查询条件之一,如果用户的姓名不为空,则将用户姓名作为查询条件之一.如果用户两个属性都为空,则查询所有用户. 我们知道,在mapper中,我们的传入参数只有一个,多个参数只能通过包转类来实现,现在这种问题怎么解决呢?答案就是在xml文件中加入判断,使sql语句动态生成.刚才的需求所对应的

MyBatis的动态SQL详解

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力.如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号.动态 SQL 可以彻底处理这种痛苦. 通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种

动态SQL

一 动态SQL /* 1.动态SQL概念的内涵 2.实现动态SQL的元素 3.if语句节点 4.choose(when,otherwise)语句节点 5.where节点 6.trim节点 7.set节点(update的set子句) 8.foreach节点 */ 1.动态SQL概念的内涵 MyBatis 最强大的特性之一就是它的动态语句功能,使用动态SQL完成多条件查 询.MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL 语中实现某些逻辑. 2.实现动态SQL的元素

mybatis——动态sql

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach if就是简单的条件判断,利用if语句我们可以实现某些简单的条件选择.先来看如下一个例子: 01 <select id="dynamicIfTest" parameterType="Blog" resultType=&

8.mybatis动态SQL模糊查询 (多参数查询,使用parameterType)

多参数查询,使用parameterType.实例: 用户User[id, name, age] 1.mysql建表并插入数据 2.Java实体类 public class User { public User() { } public User(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } private int id; private String name;