概述

where set trim 这3个标签解决了类似的问题,并且where 和 set 都属于trim的一种具体用法,下面我们通过具体的示例来学习下。


where 作用及用法

作用

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


用法

我们使用动态SQL if 元素中的例子 ,点击跳转到该示例
不使用where元素的SQL如下:

  1. <select id="selectSysUsersAdvanced" resultType="com.artisan.mybatis.xml.domain.SysUser">
  2. SELECT
  3. a.id,
  4. a.user_name userName,
  5. a.user_password userPassword,
  6. a.user_email userEmail,
  7. a.user_info userInfo,
  8. a.head_img headImg,
  9. a.create_time createTime
  10. FROM
  11. sys_user a
  12. WHERE 1=1
  13. <if test="userName != null and userName != '' ">
  14. and user_name like concat('%',#{userName},'%')
  15. </if>
  16. <if test="userEmail != null and userEmail != '' ">
  17. and user_email = #{userEmail}
  18. </if>
  19. </select>

我们在这里通过where元素来实现一遍

  1. <select id="selectSysUsersAdvancedWithWhere" resultType="com.artisan.mybatis.xml.domain.SysUser">
  2. SELECT
  3. a.id,
  4. a.user_name userName,
  5. a.user_password userPassword,
  6. a.user_email userEmail,
  7. a.user_info userInfo,
  8. a.head_img headImg,
  9. a.create_time createTime
  10. FROM
  11. sys_user a
  12. <where>
  13. <if test="userName != null and userName != '' ">
  14. and user_name like concat('%',#{userName},'%')
  15. </if>
  16. <if test="userEmail != null and userEmail != '' ">
  17. and user_email = #{userEmail}
  18. </if>
  19. </where>
  20. </select>

当if 条件都不满足的时候where元素中没有内容,所以SQL中不会出现Where。
如果if条件满足,where元素的内容就是以and开头的条件,where会自动去掉开头的and ,这也能保证where条件的正确。
相比上个案例,这种情况下生成的SQL更干净,不会在任何情况下都有where 1 = 1 这样的条件。


增加接口方法

  1. /**
  2. *
  3. *
  4. * @Title: selectSysUsersAdvancedWithWhere
  5. *
  6. * @Description: selectSysUsersAdvancedWithWhere
  7. *
  8. * @param sysUser
  9. * @return
  10. *
  11. * @return: List<SysUser>
  12. */
  13. List<SysUser> selectSysUsersAdvancedWithWhere(SysUser sysUser);

单元测试

  1. @Test
  2. public void selectSysUsersAdvancedWithWhere() {
  3. logger.info("selectSysUsersAdvancedWithWhere");
  4. // 获取SqlSession
  5. SqlSession sqlSession = getSqlSession();
  6. List<SysUser> userList = null;
  7. try {
  8. // 获取UserMapper接口
  9. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  10. logger.info("===========1.当用户只输入用户名时,需要根据用户名模糊查询===========");
  11. // 模拟前台传参 1.当用户只输入用户名时,需要根据用户名模糊查询
  12. SysUser sysUser = new SysUser();
  13. sysUser.setUserName("ad");
  14. // 调用selectSysUsersAdvanced,根据查询条件查询用户
  15. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  16. // 根据数据库sys_user表中的记录,可以匹配到admin, 期望userList不为空
  17. Assert.assertNotNull(userList);
  18. // 根据查询条件,期望只有1条数据
  19. Assert.assertTrue(userList.size() == 1);
  20. Assert.assertEquals("admin", userList.get(0).getUserName());
  21. logger.info("userList:" + userList);
  22. // 为了测试 匹配多条记录的情况,我们将id=1001这条数据的userName 由test 改为artisan
  23. sysUser.setUserName("i");
  24. // 调用selectSysUsersAdvanced,根据查询条件查询用户
  25. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  26. // 根据数据库sys_user表中的记录,可以匹配到admin和artisan, 期望userList不为空
  27. Assert.assertNotNull(userList);
  28. // 根据查询条件,期望只有2条数据
  29. Assert.assertTrue(userList.size() == 2);
  30. logger.info("userList:" + userList);
  31. logger.info("===========2.当用户只输入邮箱使,根据邮箱进行完全匹配===========");
  32. // 模拟前台传参 2.当用户只输入邮箱使,根据邮箱进行完全匹配
  33. sysUser.setUserEmail("admin@artisan.com");
  34. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  35. Assert.assertNotNull(userList);
  36. Assert.assertTrue(userList.size() == 1);
  37. logger.info(userList);
  38. sysUser.setUserEmail("1admin@artisan.com");
  39. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  40. Assert.assertTrue(userList.size() == 0);
  41. logger.info("===========3.当用户同时输入用户名和密码时,用这两个条件查询匹配的用户===========");
  42. // 模拟组合查询条件,存在记录的情况
  43. sysUser.setUserName("i");
  44. sysUser.setUserEmail("admin@artisan.com");
  45. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  46. Assert.assertNotNull(userList);
  47. Assert.assertEquals("admin@artisan.com", sysUser.getUserEmail());
  48. Assert.assertTrue(userList.size() == 1);
  49. logger.info(userList);
  50. logger.info("===========4.当用户同时输入无法匹配的用户名和密码===========");
  51. // 模拟组合查询条件,不存在记录的情况
  52. sysUser.setUserName("x");
  53. sysUser.setUserEmail("admin@artisan.com");
  54. userList = userMapper.selectSysUsersAdvancedWithWhere(sysUser);
  55. Assert.assertTrue(userList.size() == 0);
  56. logger.info(userList);
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. } finally {
  60. sqlSession.close();
  61. logger.info("sqlSession close successfully ");
  62. }
  63. }

日志

  1. 2018-04-21 21:32:11,318 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
  2. 2018-04-21 21:32:11,323 INFO [main] (BaseMapperTest.java:29) - reader close successfully
  3. 2018-04-21 21:32:11,327 INFO [main] (UserMapperTest.java:601) - selectSysUsersAdvancedWithWhere
  4. 2018-04-21 21:32:11,357 INFO [main] (UserMapperTest.java:610) - ===========1.当用户只输入用户名时,需要根据用户名模糊查询===========
  5. 2018-04-21 21:32:11,962 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%')
  6. 2018-04-21 21:32:12,046 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: ad(String)
  7. 2018-04-21 21:32:12,081 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
  8. 2018-04-21 21:32:12,082 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  9. 2018-04-21 21:32:12,091 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1
  10. 2018-04-21 21:32:12,096 INFO [main] (UserMapperTest.java:622) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
  11. 2018-04-21 21:32:12,096 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%')
  12. 2018-04-21 21:32:12,097 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String)
  13. 2018-04-21 21:32:12,098 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
  14. 2018-04-21 21:32:12,099 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  15. 2018-04-21 21:32:12,100 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  16. 2018-04-21 21:32:12,102 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 2
  17. 2018-04-21 21:32:12,104 INFO [main] (UserMapperTest.java:633) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018], SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=测试用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
  18. 2018-04-21 21:32:12,105 INFO [main] (UserMapperTest.java:635) - ===========2.当用户只输入邮箱使,根据邮箱进行完全匹配===========
  19. 2018-04-21 21:32:12,105 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ?
  20. 2018-04-21 21:32:12,106 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), admin@artisan.com(String)
  21. 2018-04-21 21:32:12,107 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
  22. 2018-04-21 21:32:12,108 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  23. 2018-04-21 21:32:12,109 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1
  24. 2018-04-21 21:32:12,109 INFO [main] (UserMapperTest.java:641) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
  25. 2018-04-21 21:32:12,110 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ?
  26. 2018-04-21 21:32:12,111 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), 1admin@artisan.com(String)
  27. 2018-04-21 21:32:12,112 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 0
  28. 2018-04-21 21:32:12,113 INFO [main] (UserMapperTest.java:647) - ===========3.当用户同时输入用户名和密码时,用这两个条件查询匹配的用户===========
  29. 2018-04-21 21:32:12,113 INFO [main] (UserMapperTest.java:655) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]]
  30. 2018-04-21 21:32:12,114 INFO [main] (UserMapperTest.java:657) - ===========4.当用户同时输入无法匹配的用户名和密码===========
  31. 2018-04-21 21:32:12,115 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ?
  32. 2018-04-21 21:32:12,116 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: x(String), admin@artisan.com(String)
  33. 2018-04-21 21:32:12,117 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 0
  34. 2018-04-21 21:32:12,117 INFO [main] (UserMapperTest.java:663) - []
  35. 2018-04-21 21:32:12,119 INFO [main] (UserMapperTest.java:669) - sqlSession close successfully

set 作用及用法

作用

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


用法

我们来改下动态SQL if 元素中的例子 跳转到改示例
修改之前的SQL如下

  1. <update id="updateSysUserByIdSelective">
  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. where id = #{id}
  24. </update>

使用set改造后的SQL如下

  1. <update id="updateSysUserByIdWithSetSelective">
  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. <!-- 如果set后面的字符串是以逗号结尾的,就将这个逗号剔除,加个逗号演示下 -->
  23. id = #{id},
  24. </set>
  25. where id = #{id}
  26. </update>

增加接口方法

  1. /**
  2. *
  3. *
  4. * @Title: updateSysUserByIdWithSetSelective
  5. *
  6. * @Description: 根据主键更新SysUser
  7. *
  8. * @param sysUser
  9. * @return
  10. *
  11. * @return: int
  12. */
  13. int updateSysUserByIdWithSetSelective(SysUser sysUser);

单元测试

  1. @Test
  2. public void updateSysUserByIdWithSetSelectiveTest() {
  3. logger.info("updateSysUserByIdWithSetSelective");
  4. // 获取SqlSession
  5. SqlSession sqlSession = getSqlSession();
  6. try {
  7. // 获取UserMapper接口
  8. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  9. // 先根据ID查询出对应的sysuser
  10. SysUser sysUser = userMapper.selectSysUserById((long) 1);
  11. // 当前数据库用户的userName期望为admin
  12. Assert.assertEquals("admin", sysUser.getUserName());
  13. // 修改用户名
  14. sysUser.setUserName("dynamicUpdate");
  15. // 修改邮件
  16. sysUser.setUserEmail("dynamicUpdate@artisan.com");
  17. // 修改用户 ,返回受影响的行数
  18. int result = userMapper.updateSysUserByIdWithSetSelective(sysUser);
  19. // 只插入一条数据 ,期望是1
  20. Assert.assertEquals(1, result);
  21. logger.info("受影响的行数:" + result);
  22. // 重新查询(虽然未提交但是在一个会话中)
  23. sysUser = userMapper.selectSysUserById((long) 1);
  24. // 期望的用户名为dynamicUpdate
  25. Assert.assertEquals("dynamicUpdate", sysUser.getUserName());
  26. // 期望的邮箱为dynamicUpdate@artisan.com
  27. Assert.assertEquals("dynamicUpdate@artisan.com", sysUser.getUserEmail());
  28. // 检查其他字段有没有被更新为null 或者 空值
  29. Assert.assertEquals("123456", sysUser.getUserPassword());
  30. Assert.assertEquals("管理员用户", sysUser.getUserInfo());
  31. logger.info(sysUser);
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. } finally {
  35. // 为了保持测试数据的干净,这里选择回滚
  36. // 由于默认的sqlSessionFactory.openSession()是不自动提交的
  37. // 除非显式的commit,否则不会提交到数据库
  38. sqlSession.rollback();
  39. logger.info("为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成");
  40. sqlSession.close();
  41. logger.info("sqlSession close successfully ");
  42. }
  43. }

日志

  1. 2018-04-21 21:30:34,774 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully
  2. 2018-04-21 21:30:34,779 INFO [main] (BaseMapperTest.java:29) - reader close successfully
  3. 2018-04-21 21:30:34,783 INFO [main] (UserMapperTest.java:675) - updateSysUserByIdWithSetSelective
  4. 2018-04-21 21:30:35,425 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: select a.id, a.user_name, a.user_password, a.user_email, a.user_info, a.head_img, a.create_time from sys_user a where id = ?
  5. 2018-04-21 21:30:35,509 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1(Long)
  6. 2018-04-21 21:30:35,551 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
  7. 2018-04-21 21:30:35,552 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  8. 2018-04-21 21:30:35,560 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1
  9. 2018-04-21 21:30:35,621 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: update sys_user SET user_name = ?, user_password = ?, user_email = ?, user_info = ?, head_img = ?, create_time = ?, id = ? where id = ?
  10. 2018-04-21 21:30:35,627 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: dynamicUpdate(String), 123456(String), dynamicUpdate@artisan.com(String), 管理员用户(String), java.io.ByteArrayInputStream@1969526c(ByteArrayInputStream), 2018-04-13 21:12:47.0(Timestamp), 1(Long), 1(Long)
  11. 2018-04-21 21:30:35,629 DEBUG [main] (BaseJdbcLogger.java:145) - <== Updates: 1
  12. 2018-04-21 21:30:35,629 INFO [main] (UserMapperTest.java:696) - 受影响的行数:1
  13. 2018-04-21 21:30:35,630 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: select a.id, a.user_name, a.user_password, a.user_email, a.user_info, a.head_img, a.create_time from sys_user a where id = ?
  14. 2018-04-21 21:30:35,631 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 1(Long)
  15. 2018-04-21 21:30:35,632 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
  16. 2018-04-21 21:30:35,633 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, dynamicUpdate, 123456, dynamicUpdate@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0
  17. 2018-04-21 21:30:35,636 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1
  18. 2018-04-21 21:30:35,637 INFO [main] (UserMapperTest.java:707) - SysUser [id=1, userName=dynamicUpdate, userPassword=123456, userEmail=dynamicUpdate@artisan.com, userInfo=管理员用户, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]
  19. 2018-04-21 21:30:35,644 INFO [main] (UserMapperTest.java:716) - 为了保持测试数据的干净,这里选择回滚,不写入mysql,请观察日志,回滚完成
  20. 2018-04-21 21:30:35,646 INFO [main] (UserMapperTest.java:719) - sqlSession close successfully

trim 作用及用法

where 和 set 标签的功能都可以用trim标签实现,并且在底层就是通过TrimSqlNode 实现的
where 标签对应的trim的实现如下

  1. <trim prefix="WHERE" prefixOverrides="ADN |OR ">
  2. ....
  3. </trim>

这里 ADN |OR 后面的空格不能省略,为了避免匹配到 andes 、orders 等单词。


set 标签对应的trim的实现如下

  1. <trim prefix="SET" suffixOverrides=",">
  2. ....
  3. </trim>

trim标签属性

属性名 含义
prefix 当trim元素包含内容时,会给内容增加prefix指定的前缀
prefixOverrides 当trim元素包含内容时,会把内容中匹配的前缀字符串去掉
suffix 当trim元素包含内容时,会给内容增加suffix指定的后缀
suffixOverrides 当trim元素包含内容时,会把内容中匹配的后缀字符串去掉