mybatis if else(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在数据库操作中,根据不同的业务场景动态生成 SQL 语句是一项核心技能。MyBatis 作为 Java 领域广受欢迎的持久层框架,提供了强大的动态 SQL 功能,其中 <if><choose> 标签是实现条件分支的核心工具。本文将通过循序渐进的方式,结合实际案例,深入解析 MyBatis 中的条件判断逻辑,帮助开发者高效掌握这一技能。


动态 SQL 的核心思想:灵活与可维护性

在传统 SQL 编写中,若需根据多个条件组合生成查询语句,通常需要通过字符串拼接或编写多套 SQL 语句,这会导致代码冗余、可读性差等问题。MyBatis 的动态 SQL 通过 XML 标签和注解,将 SQL 语句的生成逻辑与 SQL 语法解耦,实现了代码的模块化和复用。

形象比喻:可以将动态 SQL 看作一个“智能厨师”,它根据你提供的食材(参数)和菜谱(逻辑规则),自动调整烹饪步骤(SQL 语句),最终产出符合需求的菜品(查询结果)。


基础标签:<if> 的使用场景与语法

1. <if> 标签的基本语法

<if> 标签用于判断某个条件是否成立,若成立则执行标签内的 SQL 片段。其核心语法如下:

<if test="condition">  
  SQL 片段  
</if>  

其中,test 属性支持多种表达式,如直接判断字段是否非空、比较运算符(==!=)、逻辑运算符(&&||)等。

2. 典型案例:条件查询用户信息

假设需根据用户姓名或邮箱查询用户信息,可编写如下 SQL:

<select id="selectUsers" resultType="User">  
  SELECT * FROM users  
  WHERE 1=1  
  <if test="name != null">  
    AND name LIKE CONCAT('%', #{name}, '%')  
  </if>  
  <if test="email != null">  
    AND email = #{email}  
  </if>  
</select>  

解释

  • WHERE 1=1 是动态 SQL 的常见技巧,确保条件组合时无需处理 ANDOR 的前缀问题。
  • 每个 <if> 标签单独判断参数是否存在,若存在则拼接对应的条件。

3. 进阶技巧:嵌套表达式与空值处理

若需处理更复杂的条件,例如“年龄在 18 到 30 岁之间”,可以使用逻辑运算符:

<if test="ageMin != null && ageMax != null">  
  AND age BETWEEN #{ageMin} AND #{ageMax}  
</if>  

此外,对于可能为空的字段,需注意 MyBatis 的空值判断逻辑:

  • test="field":等同于 field != null
  • test="field == null":需显式判断空值。

多分支控制:<choose><when><otherwise>

当需要实现类似 if-else 的多分支逻辑时,<choose> 标签是关键。其结构与 Java 的 switch 语句类似,但支持更灵活的条件判断。

1. <choose> 标签的语法结构

<choose>  
  <when test="condition1">  
    SQL 片段1  
  </when>  
  <when test="condition2">  
    SQL 片段2  
  </when>  
  <otherwise>  
    默认 SQL 片段  
  </otherwise>  
</choose>  

核心规则

  • 按顺序匹配第一个满足条件的 <when>,执行其内容。
  • 若无符合条件的 <when>,则执行 <otherwise> 内容。

2. 实际案例:分场景查询订单状态

假设需根据参数 status 的值(如 newpaidshipped)动态生成不同的查询条件:

<select id="selectOrders" resultType="Order">  
  SELECT * FROM orders  
  WHERE 1=1  
  <choose>  
    <when test="status == 'new'">  
      AND status = 'NEW'  
    </when>  
    <when test="status == 'paid'">  
      AND status = 'PAID' AND payment_date > NOW() - INTERVAL 7 DAY  
    </when>  
    <otherwise>  
      AND status != 'CANCELED'  
    </otherwise>  
  </choose>  
</select>  

逻辑分析

  • status 参数为 new,则筛选状态为 NEW 的订单。
  • 若为 paid,则筛选状态为 PAID 且最近一周内付款的订单。
  • 其他情况则排除已取消的订单。

综合案例:动态 SQL 的复杂场景应用

案例背景

某电商平台需根据用户输入的多个筛选条件(如商品名称、价格区间、分类、库存状态)动态生成商品查询 SQL。

1. 需求拆解与标签组合

  • 商品名称模糊查询:使用 <if> 判断名称是否非空。
  • 价格区间筛选:使用 <if> 结合 BETWEEN
  • 分类多选:使用 <foreach> 遍历分类列表。
  • 库存状态选择:使用 <choose> 处理 in_stockout_of_stock 或默认值。

2. 完整 XML 配置

<select id="searchProducts" resultType="Product">  
  SELECT * FROM products  
  WHERE 1=1  
  <if test="name != null">  
    AND name LIKE CONCAT('%', #{name}, '%')  
  </if>  
  <if test="minPrice != null and maxPrice != null">  
    AND price BETWEEN #{minPrice} AND #{maxPrice}  
  </if>  
  <if test="categories != null and categories.size() > 0">  
    AND category IN  
    <foreach item="category" collection="categories"  
             open="(" separator="," close=")">  
      #{category}  
    </foreach>  
  </if>  
  <choose>  
    <when test="stockStatus == 'in_stock'">  
      AND stock > 0  
    </when>  
    <when test="stockStatus == 'out_of_stock'">  
      AND stock = 0  
    </when>  
    <!-- 默认不筛选库存状态 -->  
  </choose>  
</select>  

3. 参数传递与调用示例

Java 代码中可通过 Map 或自定义对象传递参数:

Map<String, Object> params = new HashMap<>();  
params.put("name", "手机");  
params.put("minPrice", 1000);  
params.put("maxPrice", 5000);  
params.put("categories", Arrays.asList("electronics", "phones"));  
params.put("stockStatus", "in_stock");  

List<Product> products = mapper.searchProducts(params);  

常见问题与最佳实践

1. 空值与逻辑陷阱

  • 问题:若参数 age0,直接使用 <if test="age"> 会误判为 false(因 0 等价于布尔值 false)。
  • 解决方案:显式比较 <if test="age != null">

2. 性能优化建议

  • 避免全表扫描:确保每个条件都有对应的索引支持。
  • 合并相似逻辑:若多个 <if> 条件可能生成相同 SQL 片段,可提前合并以减少冗余。

3. 调试技巧

  • 日志输出:通过 log4jmybatis.configuration.log-impl 配置,查看最终生成的 SQL 语句。
  • 单元测试:编写参数覆盖不同条件的测试用例,验证 SQL 生成的正确性。

结论

MyBatis 的 <if><choose> 标签为动态 SQL 提供了强大的灵活性,但合理的设计和严谨的测试仍是关键。通过本文的案例解析,开发者可以掌握:

  1. 如何通过 <if> 实现单条件分支。
  2. 如何利用 <choose> 构建多条件分支逻辑。
  3. 在复杂场景下组合多个标签实现灵活查询。

掌握这些技能后,开发者能够更高效地应对业务需求的变化,同时保持代码的可维护性和可读性。建议读者通过实际项目练习,并结合日志工具调试,逐步提升动态 SQL 的应用能力。

最新发布