mybatis学习11-动态SQL语句

引用文档

动态 SQL

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。

动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

主要的标签如下:

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

在实际的开发中,查询可能是多条件的,比如可能只有姓名,可能只有性别,可能有性别和姓名,

然后这些条件可以组成一个对象,根据对象包含的属性进行条件查询

mysql创建数据库

create database rainbow;
use rainbow;
CREATE TABLE `user` (
  `uid` int(11) NOT NULL auto_increment,
  `name` varchar(32) NOT NULL COMMENT '用户名称',
  `sex` char(1) default NULL COMMENT '性别',
  `addr` varchar(256) default NULL COMMENT '地址',
  PRIMARY KEY  (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.  if,也就是判断语句

test 属性中写的是对象的属性名,构成一个判断语句

在下面的案例中,where 1= 1,是为了拼接sql语句

如果没有1 = 1,再name为空的情况下,查询语句就变成了

select * from user where and sex = ?  

    <select id="findByIf" resultType="user" parameterType="user">
        select * from user 
        where 1 = 1
        <if test="name != null">
            and name like #{name}
        </if>
        <if test="sex != null">
            and sex = #{sex}
        </if>
    </select>


如果没有 1= 1 ,代码就会变成这样
    <select id="findByIf" resultType="user" parameterType="user">
        select * from user 
        where
        <if test="name != null">
            name like #{name}
        </if>
        <if test="sex != null">
            and sex = #{sex}
        </if>
    </select>     

2. where

为了简化上面 where 1=1 的条件拼装,我们可以采用<where>标签来简化开发

如果任何条件都不成立,那么就在sql语句里就不会出现where关键字

如果有任何条件成立,会自动去掉多出来的 and 或者 or

<select id="findByWhere" resultType="user" parameterType="user">
        select * from user
        <where>
            <if test="name != null">
                name like #{name}
            </if>
            <if test="sex != null">
                and sex = #{sex}
            </if>
        </where>
</select>

3. set

与where类似的,在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签:

其效果与where标签类似,有数据的时候才进行设置,它会自动将多余的逗号(,)去掉。

<update id="updateUser" parameterType="user">
        update user
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="sex != null">
                sex = #{sex},
            </if>
            <if test="addr != null">
                addr = #{addr}
            </if>
        </set>
        where uid = #{uid}
</update>

4. trim

自定义功能

trim 用来定制想要的功能,比如where和set标签都可以用trim来替换

 

下面是它涉及到的属性与解释

示例,这个与上面的where实现的效果是一样的

    <select id="findByTrim" resultType="user" parameterType="user">
        select * from user
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null">
                name like #{name}
            </if>
            <if test="sex != null">
                and sex = #{sex}
            </if>
        </trim>
    </select>

5. choose(when otherwise)

有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。

而使用if标签时,只要test中的表达式为true,就会执行if标签中的条件。

MyBatis提供了choose 元素。if标签是与(and)的关系,而choose标签是或(or)的关系.

choose标签是按顺序判断其内部when标签中的test条件出否成立,

如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行otherwise中的sql。

类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。

    <select id="findByChoose" resultType="user" parameterType="user">
        select * from user
        <where>
            <choose>
                <when test="name != null">
                    name like #{name}
                </when>
                <when test="sex != null">
                    and sex = #{sex}
                </when>
                <otherwise>
                    and uid > 5
                </otherwise>
            </choose>
        </where>
    </select>

6. foreach

oreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。

item表示集合中每一个元素进行迭代时的别名;
index指定一个名字,用于表示在迭代过程中,每次迭代到的位置;
open表示该语句以什么开始;
separator表示在每次进行迭代之间以什么符号作为分隔符;
close表示以什么结束;
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况: 
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key

<!-- select * from user where id in (1,2,3,4,5); -->
    <select id="findInIds" parameterType="uservo" resultType="user">
        select * from user
        <where>
            <if test="ids != null and ids.size() > 0">
                uid in
                <foreach collection="ids" open="(" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>


另UserVo是User的封装类

public class UserVo {
    private List<Integer> ids;
    public List<Integer> getIds() {
        return ids;
    }
    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
}

7. sql片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

提取sql片段

    <sql id="if-name-sex">
        <if test="name != null">
            name like #{name}
        </if>
        <if test="sex != null">
            and sex = #{sex}
        </if>
    </sql>

引用sql片段

    <select id="findByWhere" resultType="user" parameterType="user">
        select * from user
        <where>
            <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
            <include refid="if-name-sex"/>
            <!-- 在这里还可以引用其他的 sql 片段 -->
        </where>
    </select>

注意:

①、最好基于 单表来定义 sql 片段,提高片段的可重用性
②、在 sql 片段中不要包括 where

小结:

其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,

我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。

多在实践中使用才是熟练掌握它的技巧

 

以下是trim标签中涉及到的属性:属性描述prefix给sql语句拼接的前缀suffix给sql语句拼接的后缀prefixOverrides去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"suffixOverrides去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定————————————————版权声明:本文为CSDN博主「wt_better」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/wt_better/article/details/80992014

posted @ 2019-08-06 07:37  匆匆、  阅读(267)  评论(0编辑  收藏  举报