本篇博客主要讲解如何使用choose,where,set标签生成动态的Sql。

1. choose 用法

假设有这样1个需求:当参数id有值时优先使用id查询,当id没有值时就去判断用户名是否有值,如果有值就用用户名查询,如果没值,就使查询无结果。

首先,我们在接口SysUserMapper中添加如下方法:

  1. /**
  2. * 根据用户id或用户名查询
  3. *
  4. * @param sysUser
  5. * @return
  6. */
  7. SysUser selectByIdOrUserName(SysUser sysUser);

然后在对应的SysUserMapper.xml中添加如下代码:

  1. <select id="selectByIdOrUserName" resultType="com.zwwhnly.mybatisaction.model.SysUser">
  2. SELECT id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. create_time
  7. FROM sys_user
  8. WHERE 1 = 1
  9. <choose>
  10. <when test="id != null">
  11. AND id = #{id}
  12. </when>
  13. <when test="userName != null and userName != ''">
  14. AND user_name = #{userName}
  15. </when>
  16. <otherwise>
  17. AND 1 = 2
  18. </otherwise>
  19. </choose>
  20. </select>

注意事项:

在以上的代码中,如果没有otherwise这个限制条件,当id和userName都为null时,所有的用户都会被查询出来,但我们接口的返回值是SysUser,当查询结果是多个时就会报错。添加otherwise条件后,由于where条件不满足,因此在这种情况下就查询不到结果。

最后,在SysUserMapperTest测试类中添加如下测试方法:

  1. @Test
  2. public void testSelectByIdOrUserName() {
  3. SqlSession sqlSession = getSqlSession();
  4. try {
  5. SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
  6. // 按id查询
  7. SysUser query = new SysUser();
  8. query.setId(1L);
  9. query.setUserName("admin");
  10. SysUser sysUser = sysUserMapper.selectByIdOrUserName(query);
  11. Assert.assertNotNull(sysUser);
  12. // 只按userName查询
  13. query.setId(null);
  14. sysUser = sysUserMapper.selectByIdOrUserName(query);
  15. Assert.assertNotNull(sysUser);
  16. // id 和 userName 都为空
  17. query.setUserName(null);
  18. sysUser = sysUserMapper.selectByIdOrUserName(query);
  19. Assert.assertNull(sysUser);
  20. } finally {
  21. sqlSession.close();
  22. }
  23. }

运行测试代码,测试通过,输出日志如下:

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND user_name = ?

DEBUG [main] - ==> Parameters: admin(String)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND 1 = 2

DEBUG [main] - ==> Parameters:

DEBUG [main] - <== Total: 0

2. where 用法

where标签的作用:如果该标签包含的元素中有返回值,就插入一个where,如果where后面的字符串是以AND或者OR开头的,就将它们剔除。

假设有这样1个需求:根据用户的输入条件来查询用户列表,如果输入了用户名,就根据用户名模糊查询,如果输入了邮箱,就根据邮箱精确查询,如果同时输入了用户名和邮箱,就用这两个条件去匹配用户。

首先,我们在接口SysUserMapper中添加如下方法:

  1. /**
  2. * 根据动态条件查询用户信息(使用Where标签)
  3. *
  4. * @param sysUser
  5. * @return
  6. */
  7. List<SysUser> selectByUserWhere(SysUser sysUser);

然后在对应的SysUserMapper.xml中添加如下代码:

  1. <select id="selectByUserWhere" resultType="com.zwwhnly.mybatisaction.model.SysUser">
  2. SELECT id,
  3. user_name,
  4. user_password,
  5. user_email,
  6. create_time
  7. FROM sys_user
  8. <where>
  9. <if test="userName != null and userName != ''">
  10. AND user_name LIKE CONCAT('%',#{userName},'%')
  11. </if>
  12. <if test="userEmail != null and userEmail != ''">
  13. AND user_email = #{userEmail}
  14. </if>
  15. </where>
  16. </select>

当if条件都不满足的时候,where元素中没有内容,此时的Sql语句不会有where,语法正确。

如果if条件满足,where元素的内容就是以AND开头的条件,where会自动去掉开头的and,保证Sql语句的正确。

最后,在SysUserMapperTest测试类中添加如下测试方法:

  1. @Test
  2. public void testSelectByUserWhere() {
  3. SqlSession sqlSession = getSqlSession();
  4. try {
  5. SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
  6. // 只按用户名查询
  7. SysUser query = new SysUser();
  8. query.setUserName("ad");
  9. List<SysUser> sysUserList = sysUserMapper.selectByUserWhere(query);
  10. Assert.assertTrue(sysUserList.size() > 0);
  11. // 只按邮箱查询
  12. query = new SysUser();
  13. query.setUserEmail("test@mybatis.tk");
  14. sysUserList = sysUserMapper.selectByUserWhere(query);
  15. Assert.assertTrue(sysUserList.size() > 0);
  16. // 同时按用户民和邮箱查询
  17. query = new SysUser();
  18. query.setUserName("ad");
  19. query.setUserEmail("test@mybatis.tk");
  20. sysUserList = sysUserMapper.selectByUserWhere(query);
  21. // 由于没有同时符合这两个条件的用户,因此查询结果数为0
  22. Assert.assertTrue(sysUserList.size() == 0);
  23. } finally {
  24. sqlSession.close();
  25. }
  26. }

运行测试代码,测试通过,输出日志如下:

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE user_name LIKE CONCAT('%',?,'%')

DEBUG [main] - ==> Parameters: ad(String)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE user_email = ?

DEBUG [main] - ==> Parameters: test@mybatis.tk(String)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE user_name LIKE CONCAT('%',?,'%') AND user_email = ?

DEBUG [main] - ==> Parameters: ad(String), test@mybatis.tk(String)

DEBUG [main] - <== Total: 0

3. set 用法

set标签的作用:如果该标签包含的元素中有返回值,就插入一个set,如果set后面的字符串是以,结尾的,就将这个逗号剔除。

假设有这样1个需求:更新用户信息的时候不能将原来有值但没有发生变化的字段更新为空或null,即只更新有值的字段。

首先,我们在接口SysUserMapper中添加如下方法:

  1. /**
  2. * 根据主键选择性更新用户信息(使用Set标签)
  3. *
  4. * @param sysUser
  5. * @return
  6. */
  7. int updateByIdSelectiveSet(SysUser sysUser);

然后在对应的SysUserMapper.xml中添加如下代码:

  1. <update id="updateByIdSelectiveSet">
  2. UPDATE sys_user
  3. <set>
  4. <if test="userName != null and userName != ''">
  5. user_name = #{userName},
  6. </if>
  7. <if test="userPassword != null and userPassword != ''">
  8. user_password = #{userPassword},
  9. </if>
  10. <if test="userEmail != null and userEmail != ''">
  11. user_email = #{userEmail},
  12. </if>
  13. <if test="userInfo != null and userInfo != ''">
  14. user_info = #{userInfo},
  15. </if>
  16. <if test="headImg != null">
  17. head_img = #{headImg,jdbcType=BLOB},
  18. </if>
  19. <if test="createTime != null">
  20. create_time = #{createTime,jdbcType=TIMESTAMP},
  21. </if>
  22. id = #{id},
  23. </set>
  24. WHERE id = #{id}
  25. </update>

注意事项:为了避免所有的条件都不满足,生成的Sql语句没有set标签,因此在最后加上了id = #{id},这样必然存在的赋值。

最后,在SysUserMapperTest测试类中添加如下测试方法:

  1. @Test
  2. public void testUpdateByIdSelectiveSet() {
  3. SqlSession sqlSession = getSqlSession();
  4. try {
  5. SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
  6. SysUser sysUser = new SysUser();
  7. // 更新id=1的用户
  8. sysUser.setId(1L);
  9. // 修改邮箱
  10. sysUser.setUserEmail("test@mybatis.tk");
  11. int result = sysUserMapper.updateByIdSelectiveSet(sysUser);
  12. Assert.assertEquals(1, result);
  13. // 查询id=1的用户
  14. sysUser = sysUserMapper.selectById(1L);
  15. // 修改后的名字保持不变,但是邮箱变成了新的
  16. Assert.assertEquals("admin", sysUser.getUserName());
  17. Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
  18. } finally {
  19. sqlSession.close();
  20. }
  21. }

运行测试代码,测试通过,输出日志如下:

DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_email = ?, id = ? WHERE id = ?

DEBUG [main] - ==> Parameters: test@mybatis.tk(String), 1(Long), 1(Long)

DEBUG [main] - <== Updates: 1

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time

TRACE [main] - <== Row: 1, admin, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

4. 源码及参考

源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。

刘增辉《MyBatis从入门到精通》

原创不易,如果觉得文章能学到东西的话,欢迎点个赞、评个论、关个注,这是我坚持写作的最大动力。

如果有兴趣,欢迎添加我的微信:zwwhnly,等你来聊技术、职场、工作等话题(PS:我是一名奋斗在上海的程序员)。

MyBatis从入门到精通(七):MyBatis动态Sql之choose,where,set标签的用法的更多相关文章

  1. MyBatis基础入门《二十》动态SQL(foreach)

    MyBatis基础入门<二十>动态SQL(foreach) 1. 迭代一个集合,通常用于in条件 2. 属性 > item > index > collection : ...

  2. MyBatis基础入门《十九》动态SQL(set,trim)

    MyBatis基础入门<十九>动态SQL(set,trim) 描述: 1. 问题 : 更新用户表数据时,若某个参数为null时,会导致更新错误 2. 分析: 正确结果: 若某个参数为nul ...

  3. MyBatis基础入门《十八》动态SQL(if-where)

    MyBatis基础入门<十八>动态SQL(if-where) 描述: 代码是在<MyBatis基础入门<十七>动态SQL>基础上进行改造的,不再贴所有代码,仅贴改动 ...

  4. Mybatis学习笔记12 - 动态sql之choose(when otherwise)标签

    choose (when, otherwise):分支选择:带了break的swtich-case 示例代码: 接口定义: package com.mybatis.dao; import com.my ...

  5. MyBatis从入门到精通(六):MyBatis动态Sql之if标签的用法

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解如何使用if标签生成动 ...

  6. MyBatis从入门到精通(八):MyBatis动态Sql之foreach标签的用法

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解如何使用foreach ...

  7. MyBatis从入门到精通(第4章):MyBatis动态SQL【foreach、bind、OGNL用法】

    (第4章):MyBatis动态SQL[foreach.bind.OGNL用法] 4.4 foreach 用法 SQL 语句中有时会使用 IN 关键字,例如 id in (1,2,3).可以使用 ${i ...

  8. MyBatis从入门到精通(第9章):Spring集成MyBatis(下)

    MyBatis从入门到精通(第9章):Spring集成MyBatis(下) springmvc执行流程原理 mybatis-spring  可以帮助我们将MyBatis代码无缝整合到Spring中.使 ...

  9. MyBatis从入门到精通(第9章):Spring集成MyBatis(上)

    MyBatis从入门到精通(第9章):Spring集成MyBatis(上) Spring是一个为了解决企业级Web应用开发过程中面临的复杂性,而被创建的一个非常流行的轻量级框架. mybatis-sp ...

随机推荐

  1. QT下的几种透明效果(QPalette背景白色,窗口设置setWindowOpacity,QPainter使用Clear模式绘图)

    1.窗口整体透明,但是窗体上的控件不透明.    通过设置窗体的背景色来实现,将背景色设置为全透. QPalette pal = palette(); pal.setColor(QPalette::B ...

  2. 使用 Capistrano 和写作 Ruby 迭代边缘部署

    想边自己写ruby代码,边部署随时能够到处查看,heroku域名又不友好,速度在国内又慢.于是乎想起来capistrano,于是学起 ... capistrano 一点入门认知 https://www ...

  3. 2-18-搭建mysql集群实现高可用

          1 环境清理以及安装 1.1  mysql旧版本清除 准备5台虚拟机,分配如下 mysql管理结点:xuegod1.cn IP:192.168.10.31  (安装server.clien ...

  4. NoSQL Manager for MongoDB 4.6.0.3 带key

    NoSQL Manager for MongoDB 4.6.0.3 是一个Windows平台的MongoDB高级管理工具.请低调使用. 博客园文件一次最大不超过10M. 官方安装包: mongodbm ...

  5. Vmware 占用宿主机硬盘空间只增不减

    问题: vmware 占用硬盘空间只增大不减少.即使你删除虚拟机系统里面的文件,占用宿主机的硬盘空间也不释放.用了一段时间后空间不够了. 解决办法: 方法一: 把一部分*sxxx.vmdk文件剪切到其 ...

  6. 通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)

    原文:通通WPF随笔(4)--通通手写输入法(基于Tablet pc实现) 从我在博客园写第一篇博客到现在已经有1年半了,我的第一篇博客写的就是手写识别,当时,客户需求在应用中加入手写输入功能,由于第 ...

  7. WPF使用NAudio录音

    代码: using NAudio.Wave; using System.Windows; namespace NAudioDemo { /// <summary> /// MainWind ...

  8. ExtJS 折线图趟过的坑

    问题: 1.根据条件检索后绘制折线图,之前的坐标没有清除如图 解决方案: 在绘制之前,清空坐票: leftLine.surface.removeAll(); leftLine.redraw(false ...

  9. Android零基础入门第68节:完善RecyclerView,添加首尾视图

    在之前学习ListView的时候,有学习过如何给ListView添加列表头和列表尾.但是通过近几期的学习,发现RecyclerView是一个比ListView更加强大和灵活的组件,今天一起来学习如何给 ...

  10. 宿主机与虚拟机系统的USB设备切换

    有时候我们需要在虚拟机的操作系统中进行一些USB设备的测试,但默认情况下USB设备是在宿主机系统里面的,那这个时候我们就要进行切换才能够达到目的,具体要怎么操作呢?下面讲解一下:   1. Ctrl+ ...