开发者

MyBatis-Plus 中 的动态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 片段
  • 六、总结

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

    一、什么是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 user
        WHERE age > 18
        ${ew.customSqlSegment}  <!-- 插入 Wrapper 的条件 -->
    </select&g编程客栈t;

    Java 调用

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

    生成 SQL

    SELECT * FROM user
    WHERE age > 18
      AND 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 userjs 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 user
        WHERE <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 u
        LEFT JOIN role r ON u.role_id = r.id
        ${ew.customSqlSegment}
    </select>

    六、总结

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

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

    到此这篇关于MyBatis-Plus 中 的动态SQL 片段(sqlSegment)讲解的文章就介绍到这了,更多相关MyBatis-Plus动态SQL内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜