Mybatis之旅第四篇-动态SQL

一、引言

在之前的CRUD例子中,都是一些很简单的SQL,然而实际的业务开发中会有一些复杂的SQL,我们经常需要拼接SQL,拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。Mybatis个一个强大特性--动态SQL,这一特性可以彻底摆脱这种痛苦。

二、if标签

现在有如下查询:

<!-- 根据条件查询用户 --><select id="queryUserByWhere" parameterType="user" resultType="user">      SELECT id, username, birthday, sex, address FROM `user`

        WHERE sex = #{sex} AND username LIKE

      '%${username}%'

    </select>

当我们带入两个参数时,返回结果不会有问题,可是当我们只带入姓名,不带入性别时,结果就不合理,因为sex带入的null,作为查询条件就过滤了结果,这个时候我们需要if标签。

改造sql:

<!-- 根据条件查询用户 --><select id="queryUserByWhere" parameterType="user" resultType="user">  SELECT id, username, birthday, sex, address FROM `user`

    WHERE 1=1

  <if test="sex!=null and sex !=''">    AND sex = #{sex}

  </if><if test="username!=null and username!=''">  AND username like

  '%${username}%'

  </if></select>

将接口和方法都加入其中

@Testpublicvoid testQueryUserByWhere() {

    // mybatis和spring整合,整合之后,交给spring管理SqlSession sqlSession =this.sqlSessionFactory.openSession();

    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    // 使用userMapper执行根据条件查询用户User user =new User();

    //user.setSex("1");user.setUsername("张");

    Listlist = userMapper.queryUserByWhere(user);

    for (User u : list) {

        System.out.println(u);

    }

    // mybatis和spring整合,整合之后,交给spring管理    sqlSession.close();

}

结果:

三、where 标签

where标签会把第一个and忽略,当然如果是or开头的,MyBatis也会把它忽略,此外,在where元素中你不需要考虑空格的问题,MyBatis会智能的帮你加上。

<select id="queryUserByWhere1" parameterType="user" resultType="user">    SELECT id, username, birthday, sex, address FROM `user`

    <!-- where标签可以自动添加where,同时处理sql语句中第一个and或者or关键字 --><where><if test="sex!=null">            AND sex = #{sex}

        </if><if test="username!=null and username!=''">            AND username like

            '%${username}%'

        </if></where></select>

四、set 标签

在更新的时候我们也需要像where一样能够进行动态判断,这个时候就使用set标签,set会使最后的逗号忽略,我们就可以动态的更新那些修改了的字段。

如下:

<update id="dynamicSetTest" parameterType="user">    update `user`

    <set><if test="sex != null">            sex = #{sex},

        </if><if test="username!=null and username!=''">            username = #{username},

        </if></set>    where id = #{id}</update>

测试:

@Testpublicvoid dynamicSetTest() {

    SqlSession sqlSession =this.sqlSessionFactory.openSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    User user =new User();

    //user.setSex("1");user.setUsername("袁大大");

    user.setId(26);

    userMapper.dynamicSetTest(user);

    sqlSession.commit();

    sqlSession.close();

}

五、choose(when,otherwise) 标签

choose的作用类似Java语言中的switch,可以解决我们只想选择一个查询条件的情况。

如下:

<select id="selectUserByChoose" resultType="user" parameterType="user">        select id, username, birthday, sex, address FROM `user`

        <where><choose><when test="id !='' and id != null">                    id=#{id}

                </when><when test="username !='' and username != null">                    and username like #{username}

                </when><otherwise>                    and sex=#{sex}

                </otherwise></choose></where></select>

这个写法很容易理解,与switch相同,匹配成功后就会跳出。

六、trim 标签

trim标记是一个格式化的标记,可以完成set或者是where标记的功能,怎么用呢:

增加prefix前缀,去掉第一个prefixoverride中内容。

增加suffix后缀,去掉最后一个suffixoverride中内容。

通过trim可以解决where 与set 问题

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="user">    select * from user

    <!-- <where>

        <if test="username != null">

          username=#{username}

        </if>

        <if test="username != null">

          and sex=#{sex}

        </if>

    </where>  --><trim prefix="where" prefixOverrides="and | or"><if test="username != null">            and username=#{username}

        </if><if test="sex != null">            and sex=#{sex}

        </if></trim></select>

先增加where,并去掉第一个and 或者or ,替换了where if 写法。

<!-- 根据 id 更新 user 表的数据 --><update id="updateUserById" parameterType="com.ys.po.User">        update user u

            <!-- <set>

                <if test="username != null and username != ''">

                    u.username = #{username},

                </if>

                <if test="sex != null and sex != ''">

                    u.sex = #{sex}

                </if>

            </set> --><trim prefix="set" suffixOverrides=","><if test="username != null and username != ''">                    u.username = #{username},

                </if><if test="sex != null and sex != ''">                    u.sex = #{sex},

                </if></trim>       

        where id=#{id}

    </update>

增加set,并去掉最后一个逗号,替换了set if写法。

七、SQL片段

写sql时经常会出现一些重复片段,我们可以进行提取,这样可以做到重用。

先使用sql进行声明:

<!-- 声明sql片段 --><sql id="userFields">  id, username, birthday, sex, address</sql>

使用include refid

<select id="queryUserBySqlWhere" parameterType="user" resultType="user"><!-- SELECT id, username, birthday, sex, address FROM `user` --><!-- 使用include标签加载sql片段;refid是sql片段id -->SELECT <include refid ="userFields"/> FROM `user`<!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --><where><if test="sex != null">    AND sex = #{sex}</if><if test="username != null and username != ''">AND username LIKE

'%${username}%'

</if></where></select>

八、foreach标签

当我们向sql传递数组或List,mybatis使用foreach解析。

foreach标签,进行遍历

collection:遍历的集合,这里是QueryVo的ids属性

item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致

open:在前面添加的sql片段

close:在结尾处添加的sql片段

separator:指定遍历的元素之间使用的分隔符

<select id="queryUserByIds" parameterType="com.yuanqinnan.pojo.QueryVo" resultType="user">SELECT * FROM `user`<where><foreach collection="ids" item="item" open="id IN (" close=")"    separator=",">    #{item}</foreach>

改造QueryVo:

@Data

public class QueryVo {

    private User user;

    private List<Integer> ids;

}

测试方法:

@Testpublicvoid queryUserByIds(){

    SqlSession sqlSession =this.sqlSessionFactory.openSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    QueryVo user =new QueryVo();

    Listids =newArrayList<>();

    ids.add(1);

    ids.add(10);

    ids.add(24);

    user.setIds(ids);

    List list = userMapper.queryUserByIds(user);

    for (User u : list) {

        System.out.println(u);

    }

    sqlSession.close();

}

结果

动态sql其实是一个拼接过程,我们掌握上面这些标签,就能完成mybatis的动态sql

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容