MyBatis动态Sql之if标签的用法详解

最近在读刘增辉老师所著的《MyBatis从入门到精通》一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸!

本篇博客主要讲解如何使用if标签生成动态的Sql,主要包含以下3个场景:

1.根据查询条件实现动态查询
2.根据参数值实现动态更新某些列
3.根据参数值实现动态插入某些列

1. 使用if标签实现动态查询

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

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

/**
 * 根据动态条件查询用户信息
 *
 * @param sysUser
 * @return
 */
List<SysUser> selectByUser(SysUser sysUser);

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

<select id="selectByUser" resultType="com.zwwhnly.mybatisaction.model.SysUser">
  SELECT id,
      user_name,
      user_password,
      user_email,
      create_time
  FROM sys_user
  WHERE 1 = 1
  <if test="userName != null and userName != ''">
    AND user_name LIKE CONCAT('%',#{userName},'%')
  </if>
  <if test="userEmail != null and userEmail != ''">
    AND user_email = #{userEmail}
  </if>
</select>

代码简单讲解:

1)if标签的test属性必填,该属性值是一个符合OGNL要求的判断表达式,一般只用true或false作为结果。

2)判断条件property != null 或 property == null,适用于任何类型的字段,用于判断属性值是否为空。

3)判断条件property != '' 或 property == '',仅适用于String类型的字段,用于判断是否为空字符串。

4)当有多个判断条件时,使用and或or进行连接,嵌套的判断可以使用小括号分组,and相当于Java中的与(&&),or相关于Java中的或(||)。

所以上面代码的意思就是先判断字段是否为null,然后再判断字段是否为空字符串。

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

@Test
public void testSelectByUser() {
  SqlSession sqlSession = getSqlSession();
  try {
    SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
    // 只按用户名查询
    SysUser query = new SysUser();
    query.setUserName("ad");
    List<SysUser> sysUserList = sysUserMapper.selectByUser(query);
    Assert.assertTrue(sysUserList.size() > 0);
    // 只按邮箱查询
    query = new SysUser();
    query.setUserEmail("test@mybatis.tk");
    sysUserList = sysUserMapper.selectByUser(query);
    Assert.assertTrue(sysUserList.size() > 0);
    // 同时按用户民和邮箱查询
    query = new SysUser();
    query.setUserName("ad");
    query.setUserEmail("test@mybatis.tk");
    sysUserList = sysUserMapper.selectByUser(query);
    // 由于没有同时符合这两个条件的用户,因此查询结果数为0
    Assert.assertTrue(sysUserList.size() == 0);
  } finally {
    sqlSession.close();
  }
}

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

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND 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 1 = 1 AND 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 1 = 1 AND user_name LIKE CONCAT('%',?,'%') AND user_email = ?
DEBUG [main] - ==> Parameters: ad(String), test@mybatis.tk(String)
DEBUG [main] - <== Total: 0

2. 使用if标签实现动态更新

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

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

/**
 * 根据主键选择性更新用户信息
 *
 * @param sysUser
 * @return
 */
int updateByIdSelective(SysUser sysUser);

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

<update id="updateByIdSelective">
  UPDATE sys_user
  SET
  <if test="userName != null and userName != ''">
    user_name = #{userName},
  </if>
  <if test="userPassword != null and userPassword != ''">
    user_password = #{userPassword},
  </if>
  <if test="userEmail != null and userEmail != ''">
    user_email = #{userEmail},
  </if>
  <if test="userInfo != null and userInfo != ''">
    user_info = #{userInfo},
  </if>
  <if test="headImg != null">
    head_img = #{headImg,jdbcType=BLOB},
  </if>
  <if test="createTime != null">
    create_time = #{createTime,jdbcType=TIMESTAMP},
  </if>
  id = #{id}
  WHERE id = #{id}
</update>

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

@Test
public void testUpdateByIdSelective() {
  SqlSession sqlSession = getSqlSession();
  try {
    SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
    SysUser sysUser = new SysUser();
    // 更新id=1的用户
    sysUser.setId(1L);
    // 修改邮箱
    sysUser.setUserEmail("test@mybatis.tk");
    int result = sysUserMapper.updateByIdSelective(sysUser);
    Assert.assertEquals(1, result);
    // 查询id=1的用户
    sysUser = sysUserMapper.selectById(1L);
    // 修改后的名字保持不变,但是邮箱变成了新的
    Assert.assertEquals("admin", sysUser.getUserName());
    Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
  } finally {
    sqlSession.close();
  }
}

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

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

3. 使用if标签实现动态插入

假设有这样1个需求:往数据库表中插入数据的时候,如果某一列的参数值不为空,就使用传入的值,如果传入的参数值为空,就使用数据库中的默认值(通常是空),而不使用传入的空值。

为了更好的理解该示例,我们先给sys_user表的user_email字段设置默认值:test@mybatis.tk,Sql语句如下:

ALTER TABLE sys_user
MODIFY COLUMN user_email VARCHAR(50) NULL DEFAULT 'test@mybatis.tk'
COMMENT '邮箱'
AFTER user_password;

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

/**
 * 根据传入的参数值动态插入列
 *
 * @param sysUser
 * @return
 */
int insertSelective(SysUser sysUser);

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

<insert id="insertSelective" useGeneratedKeys="true" keyProperty="id">
  INSERT INTO sys_user(user_name, user_password,
  <if test="userEmail != null and userEmail != ''">
    user_email,
  </if>
  user_info, head_img, create_time)
  VALUES (#{userName},#{userPassword},
  <if test="userEmail != null and userEmail != ''">
    #{userEmail},
  </if>
  #{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
</insert>

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

@Test
public void testInsertSelective() {
  SqlSession sqlSession = getSqlSession();
  try {
    SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
    SysUser sysUser = new SysUser();
    sysUser.setUserName("test-selective");
    sysUser.setUserPassword("123456");
    sysUser.setUserInfo("test info");
    sysUser.setCreateTime(new Date());
    sysUserMapper.insertSelective(sysUser);
    // 获取刚刚插入的数据
    sysUser = sysUserMapper.selectById(sysUser.getId());
    // 因为没有指定userEmail,所以用的是数据库的默认值
    Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
  } finally {
    sqlSession.close();
  }
}

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

DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_info, head_img, create_time) VALUES (?,?, ?,?,?)
DEBUG [main] - ==> Parameters: test-selective(String), 123456(String), test info(String), null, 2019-07-08 11:40:36.927(Timestamp)
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: 1021(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1021, test-selective, 123456, test@mybatis.tk, 2019-07-08 11:40:37.0
DEBUG [main] - <== Total: 1

4. 源码

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

总结

以上所述是小编给大家介绍的MyBatis动态Sql之if标签的用法详解 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

时间: 2019-07-08

mybatis 映射文件中if标签判断字符串相等的两种方式

mybatis 映射文件中,if标签判断字符串相等,两种方式: 因为mybatis映射文件,是使用的ognl表达式,所以在判断字符串sex变量是否是字符串Y的时候, <if test="sex=='Y'.toString()"> <if test = 'sex== "Y"'> 注意: 不能使用 <if test="sex=='Y'"> and 1=1 </if> 因为mybatis会把'Y'解析为字

MyBatis动态SQL中的trim标签的使用方法

trim标记是一个格式化的标记,可以完成set或者是where标记的功能,如下代码: 1. select * from user <trim prefix="WHERE" prefixoverride="AND |OR"> <if test="name != null and name.length()>0"> AND name=#{name}</if> <if test="gender

MyBatis动态SQL标签用法实例详解

1.动态SQL片段 通过SQL片段达到代码复用 <!-- 动态条件分页查询 --> <sql id="sql_count"> select count(*) </sql> <sql id="sql_select"> select * </sql> <sql id="sql_where"> from icp <dynamic prepend="where&quo

Mybatis高级映射、动态SQL及获得自增主键的解析

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .下文给大家介绍Mybatis高级映射.动态SQL及获得自增主键的内容,具体详情请参考本文. 一.动态SQL 相信大家在用mybatis操作数据库时时都会碰到一个问题,假如现在我们有一个关于作者的list authorList,需要根据authorList里已有的作者信息在数据库中查询相应作者的博客信息.

Mybatis传单个参数和&lt;if&gt;标签同时使用的问题及解决方法

// Mapper.java EmerEvent selectByAlarmId(Integer alarmId); // Mapper.xml <select id="selectByAlarmId" resultMap="BaseResultMap" parameterType="java.lang.Integer"> select <include refid="Base_Column_List" /&

Spring3 整合MyBatis3 配置多数据源动态选择SqlSessionFactory详细教程

一.摘要 这篇文章将介绍Spring整合Mybatis 如何完成SqlSessionFactory的动态切换的.并且会简单的介绍下MyBatis整合Spring中的官方的相关代码. Spring整合MyBatis切换SqlSessionFactory有两种方法 第一. 继承SqlSessionDaoSupport,重写获取SqlSessionFactory的方法. 第二.继承SqlSessionTemplate 重写getSqlSessionFactory.getConfiguration和Sq

Mybatis中动态SQL,if,where,foreach的使用教程详解

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.statement中直接定义使用动态SQL: 在statement中利用if 和 where 条件组合达到我们的需求,通过一个例子来说明: 原SQL语句

Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解

StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程中,它的start: // Start our child containers, if any Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < childre

如何在Spring Boot应用中优雅的使用Date和LocalDateTime的教程详解

Java8已经发布很多年了,但是很多人在开发时仍然坚持使用着Date和SimpleDateFormat进行时间操作.SimpleDateFormat不是线程安全的,而Date处理时间很麻烦,所以Java8提供了LocalDateTime.LocalDate和LocalTime等全新的时间操作API.无论是Date还是LocalDate,在开发Spring Boot应用时经常需要在每个实体类的日期字段上加上@DateTimeFormat注解来接收前端传值与日期字段绑定,加上@JsonFormat注

MyBatis中动态sql的实现方法示例

1. 动态sql 动态sql是mybatis中的一个核心,什么是动态sql? 动态sql即对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. MyBatis的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号.有些时候,SQL语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可

mysql存储过程 在动态SQL内获取返回值的方法详解

MySql通用分页存储过程过程参数 复制代码 代码如下: p_cloumns varchar(500),p_tables varchar(100),p_where varchar(4000),p_order varchar(100),p_pageindex int,p_pagesize int,out p_recordcount int,out p_pagecount int $:begin    declare v_sqlcounts varchar(4000);    declare v_s

Pycharm中切换pytorch的环境和配置的教程详解

pytorch安装 注:在训练模型的时候,有时候可能需要不同版本的 torch和torchvision,所以需要配置不同的环境.anconda和pycharm自行安装,接下来在pycharm终端pip安装. 1. torch和torchvision下载 进入pytorch官网,[https://pytorch.org] 进入右下角的网站下载,找到需要的版本,我的版本如下 1.3.0-版本 cp37-python版本3.7 win-Windows系统 2. pycharm终端安装 (1)首先创建一

oracle+mybatis 使用动态Sql当插入字段不确定的情况下实现批量insert

最近做项目遇到一个挺纠结的问题,由于业务的关系,DB的数据表无法确定,在使用过程中字段可能会增加,这样在insert时给我造成了很大的困扰. 先来看一下最终我是怎么实现的: <insert id="batchInsertLine" parameterType="HashMap"> <![CDATA[ INSERT INTO tg_fcst_lines(${lineColumn}) select result.*,sq_fcst_lines.next

mybatis的动态sql详解(精)

MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力.如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号.动态 SQL 可以彻底处理这种痛苦. 通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中. 动态SQL元素和使用 JSTL或其他相似的基于XML的文本处理器相似.在MyBatis之前的版本中,有很多

MyBatis使用动态SQL标签的小陷阱

MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 现在MyBatis越来越受大家的喜爱了,它的优势大家都知道,我就不多说了,直接说重点. MyBatis中提供动态SQL功能,我们可以使用<if><when&

MyBatis的动态SQL语句实现

1. 动态SQL之<if>标签 我们根据实体类的不同取值,使用不同的SQL语句来进行查询.比如在id如果不为空时可以根据id查询,如果username不为空时还要加入用户名作为条件,这种情况在我们的多条件组合查询中经常会碰到. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN&qu