当前位置: 首页 > news >正文

MyBatis-Plus 中 的动态SQL 片段(sqlSegment)讲解

以下是针对 MyBatis-Plus 中 通用 SQL 片段(sqlSegment) 的清晰详解,结合核心功能与实用场景,逐步说明其用法:


通用 SQL 片段(sqlSegment)

    • 一、什么是 `sqlSegment`?
    • 二、核心使用方式
      • 1. **条件构造器(Wrapper)动态生成 SQL 片段**
      • 2. **在 XML 中引用 Wrapper 的 SQL 片段**
    • 三、关键语法解析
      • 1. **`${ew.customSqlSegment}` 的作用**
      • 2. **Lambda 表达式避免硬编码字段名**
      • 3. **${ew.customSqlSegment} 与 ${ew.sqlSegment} 的区别对比**
    • 四、实际应用场景
      • 场景 1:动态条件查询
      • 场景 2:复用公共 SQL 片段
      • 场景 3:逻辑删除自动过滤
    • 五、最佳实践与避坑指南
      • 1. **优先使用 LambdaQueryWrapper**
      • 2. **谨慎使用 `${}` 防止 SQL 注入**
      • 3. **复杂 SQL 结合 XML 片段**
    • 六、总结

一、什么是 sqlSegment

在 MyBatis-Plus 中,sqlSegment 通常指 动态生成的 SQL 代码块,例如由条件构造器(Wrapper)自动生成的 WHERE 条件、ORDER BY 排序等。开发者可通过特定语法(如 ${ew.customSqlSegment}或者${ew.sqlSegment})将这些片段插入到自定义 SQL 中,实现灵活组合。


二、核心使用方式

1. 条件构造器(Wrapper)动态生成 SQL 片段

通过 QueryWrapperLambdaQueryWrapper 构建条件,自动生成 WHERE 后的条件语句。

// 创建 Wrapper
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1).like("username", "Tom").orderByDesc("create_time");// 执行查询(自动拼接条件到 SQL)
List<User> users = userMapper.selectList(wrapper);

生成 SQL

SELECT * FROM user 
WHERE status = 1 AND username LIKE '%Tom%' 
ORDER BY create_time DESC

2. 在 XML 中引用 Wrapper 的 SQL 片段

使用 ${ew.customSqlSegment} 占位符,将 Wrapper 中的条件插入到自定义 SQL。

<!-- XML 映射文件 -->
<select id="selectByWrapper" resultType="User">SELECT * FROM userWHERE age > 18${ew.customSqlSegment}  <!-- 插入 Wrapper 的条件 -->
</select>

Java 调用

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ne("email", null);  // 添加条件:email IS NOT NULL
List<User> users = userMapper.selectByWrapper(wrapper);

生成 SQL

SELECT * FROM user
WHERE age > 18AND email IS NOT NULL  <!-- 来自 Wrapper -->

三、关键语法解析

1. ${ew.customSqlSegment} 的作用

  • ew 是 MyBatis-Plus 的固定参数名,代表 Wrapper 对象。
  • customSqlSegmentWrapper 中生成的 SQL 片段(如 WHERE 条件、ORDER BY)。
  • 注意:必须确保 Wrapper 对象作为参数传递到 XML 中(通常参数名为 ew)。

2. Lambda 表达式避免硬编码字段名

使用 LambdaQueryWrapper 提升代码安全性和可读性:

LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(User::getStatus, 1)         // 方法引用代替字符串.ge(User::getAge, 18).orderByAsc(User::getCreateTime);

3. ${ew.customSqlSegment} 与 ${ew.sqlSegment} 的区别对比

‌1.${ew.customSqlSegment}‌:‌动态拼接完整 WHERE 条件‌:常用于无需手动编写 WHERE 的自定义 SQL 中

2.‌${ew.sqlSegment}‌:‌仅注入条件表达式‌:需手动拼接 WHERE,适用于需要精确控制 SQL 结构的场景

// Mapper 接口  
@Select("SELECT * FROM user ${ew.customSqlSegment}")  
List<User> selectPageCustom(@Param(Constants.WRAPPER) Wrapper<User> wrapper);  @Select("SELECT * FROM user WHERE ${ew.sqlSegment}")  
List<User> selectPageWhere(@Param(Constants.WRAPPER) Wrapper<User> wrapper);  

四、实际应用场景

场景 1:动态条件查询

根据用户输入动态拼接查询条件,无需手动编写 if 判断。

public List<User> searchUsers(String name, Integer minAge) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.like(StringUtils.isNotBlank(name), User::getUsername, name).ge(minAge != null, User::getAge, minAge);return userMapper.selectList(wrapper);
}
  • likege 方法中的第一个参数为条件布尔值,自动决定是否拼接该条件。

场景 2:复用公共 SQL 片段

在 XML 中定义公共片段,结合 Wrapper 实现复用。

<!-- 定义公共的 WHERE 条件 -->
<sql id="activeUser">is_deleted = 0 AND status = 'ACTIVE'
</sql><!-- 在查询中复用 -->
<select id="selectActiveUsers" resultType="User">SELECT * FROM userWHERE <include refid="activeUser"/>${ew.customSqlSegment}  <!-- 追加其他动态条件 -->
</select>

Java 调用

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("username", "Admin");
List<User> users = userMapper.selectActiveUsers(wrapper);

生成 SQL

SELECT * FROM user
WHERE is_deleted = 0 AND status = 'ACTIVE'  <!-- 公共片段 -->AND username LIKE '%Admin%'              <!-- 动态条件 -->

场景 3:逻辑删除自动过滤

配置 MyBatis-Plus 全局逻辑删除,自动在所有查询中注入 WHERE is_deleted=0

# application.yml
mybatis-plus:global-config:db-config:logic-delete-field: isDeleted   # 实体类字段名logic-delete-value: 1           # 删除后的值logic-not-delete-value: 0       # 未删除的值
  • 无需手动编写条件,删除操作自动变为 UPDATE 语句,查询自动过滤已删除数据。

五、最佳实践与避坑指南

1. 优先使用 LambdaQueryWrapper

  • 优势:避免字段名硬编码,编译时检查,重构友好。
  • 示例
    lambdaWrapper.eq(User::getStatus, 1)  // 正确性由编译器保证
    

2. 谨慎使用 ${} 防止 SQL 注入

  • 安全写法
    WHERE username = #{param}    <!-- 使用 #{} 预编译 -->
    
  • 风险写法
    ORDER BY ${orderBy}          <!-- 直接拼接字符串,需手动过滤参数 -->
    

3. 复杂 SQL 结合 XML 片段

对于多表 JOIN 或复杂统计,仍可在 XML 中编写完整 SQL,利用 <include> 复用片段。

<select id="selectUserWithRole" resultType="map">SELECT u.*, r.role_name FROM user uLEFT JOIN role r ON u.role_id = r.id${ew.customSqlSegment}
</select>

六、总结

  • 核心机制:通过 Wrapper 生成动态 SQL 片段,结合 ${ew.customSqlSegment} 嵌入自定义 SQL。
  • 适用场景:动态条件查询、逻辑删除、多租户隔离、公共代码复用。
  • 优势:减少重复代码、提升可维护性、保持 SQL 灵活性。

通过合理利用 MyBatis-Plus 的 SQL 片段功能,可显著简化开发流程,尤其适合快速迭代的中大型项目。

http://www.xdnf.cn/news/660907.html

相关文章:

  • 速卖通,国际站测评补单,如何平衡效率和安全
  • C++ ——new和malloc的区别(详细)
  • GROMACS 本地部署教程:模拟生命密码,解码科学未来!
  • 力扣面试150题--二叉搜索树迭代器
  • Spring参数解析异常:Name for argument of type [java.lang.String] not specified 深度解析
  • 【Spring AI集成实战】基于NVIDIA LLM API构建智能聊天应用:从配置到函数调用全解析
  • PT_THREAD 的嵌套协程示例
  • 唯一原生适配鸿蒙电脑的远程控制应用,向日葵正式上线
  • MyBatis-Plus 深度解析与高效实践指南
  • Spring Security6.5 菜鸟教程
  • HarmonyOS NEXT~HarmonyOS 语言仓颉:下一代分布式开发语言的技术解析与应用实践
  • PostgreSQL 权限问题解决方案查看磁盘多少GB 已使用多少GB
  • 20250526-C++基础-函数指针
  • Pyhton_25_5_26
  • 中断和异常
  • 2025-05-26 什么是“AI 全栈”
  • K8s中间件Kafka上云部署
  • Treasures in Discarded Weights for LLM Quantization阅读
  • 华为OD机试_2025 B卷_欢乐的周末(Python,100分)(附详细解题思路)
  • Anaconda 在 Windows 上的安装教程
  • SpringBoot3集成Oauth2.1——7数据库存储用户信息
  • 基于DDD的企业团餐订餐平台微服务架构设计与实现(二)
  • GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【二】
  • sd webui 安装sd-webui-TemporalKit 加载报错解决办法
  • Java-ArrayList集合的遍历方式详解
  • uni-app学习笔记十五-vue3中defineExpose的使用
  • 如何用Python搭建一个网站
  • Qwen-Agent的使用示例-天气查询
  • Spring + MyBatis/MyBatis-Plus 分页方案(limit分页和游标分页)详解
  • 【排错】kylinLinx环境python读json文件报错UTF-8 BOM