欢迎光临
我们一直在努力

MySQL 动态 SQL 实战

目录

一、先明确:什么时候必须用动态 SQL?

二、应用层动态 SQL(生产 99% 场景)

2.1 MyBatis 动态 SQL(标签体系 + 实战案例)

核心标签速览

实战场景 1:多条件分页查询(最经典)

1) Mapper 接口

2) 入参实体

3) Mapper.xml 动态 SQL(标准写法)

关键点解析

实战场景 2:动态更新(部分字段更新)

标准写法

标签

特性

拓展:用 自定义(万能替代 where/set)

实战场景 3:互斥条件(choose/when 多分支)

实战场景 4:IN 查询 + 遍历集合

语法说明

示例 1:IN 批量查询

示例 2:批量插入(高频实战)

实战场景 5:动态排序(前端传排序字段 + 升降序)

业务:前端传 sortField 排序字段、sortOrder 升降序(ASC/DESC)

安全避坑(重中之重)

实战场景 6:动态表名(分表 / 按月日志表)

2.2 MyBatis-Plus 动态 SQL(简化开发)

1) 多条件查询(等价上面 XML 多条件)

2) 动态更新(仅更新非空字段)

三、MySQL 原生动态 SQL(存储过程 + PREPARE)

语法

简单示例:动态条件查询存储过程

四、动态 SQL 核心风险 & 生产避坑(面试高频)

4.1 SQL 注入(最严重)

两种占位符区别(必背)

注入攻击演示

4.2 索引失效问题

4.3 性能问题

4.4 语法报错

五、面试高频问答(总结)

六、生产最佳实践总结


动态 SQL 核心是运行时拼接 SQL 语句,解决查询条件不固定、表名 / 列名动态、分页 / 排序动态等场景,MySQL 中主要分两类实现:

  • 应用层动态 SQL(Java/PHP 等代码拼接,主流)
  • MySQL 原生动态 SQL(存储过程 + PREPARE/EXECUTE,少用)
  • 本文结合业务实战场景、MyBatis/MyBatis-Plus 主流框架、原生语法、性能 & 安全避坑逐一讲解。


    一、先明确:什么时候必须用动态 SQL?

    固定 SQL 无法满足的场景:

  • 多条件组合查询(前端可选填查询项,如姓名、手机号、状态、时间范围)
  • 动态排序 / 分页(前端传排序字段、升降序、页码)
  • 动态表名(分表、日志表、按月分表、租户隔离表)
  • 动态列(动态展示字段、动态更新部分字段)
  • 批量操作(批量插入、批量更新,条数不固定)
  • 原则:能写静态 SQL 绝不使用动态 SQL,动态 SQL 有注入风险、索引失效、可读性差问题。


    二、应用层动态 SQL(生产 99% 场景)

    Java 生态以 MyBatis / MyBatis-Plus 为核心,是企业最常用方案。

    2.1 MyBatis 动态 SQL(标签体系 + 实战案例)

    MyBatis 内置一套OGNL 动态标签,无需手动拼接字符串,防注入、语法优雅。

    核心标签速览

    标签
    作用
    <if> 单条件判断(最常用)
    <where> 自动处理 and/or、去除首部多余 and
    <trim> 自定义截取前缀 / 后缀(替代 where/set)
    <set> 更新语句专用,去除尾部多余 ,
    <choose>/<when>/<otherwise> 多分支互斥判断(类似 if-else if-else)
    <foreach> 遍历集合(in 查询、批量插入 / 更新)
    <bind> 绑定变量,拼接模糊查询 %,优化索引

    实战场景 1:多条件分页查询(最经典)

    业务:用户列表查询,前端可传:用户名 (模糊)、状态、手机号、开始时间、结束时间,条件非必选。

    1) Mapper 接口

    // 入参:查询实体
    List<User> selectUserList(UserQuery query);

    2) 入参实体

    @Data
    public class UserQuery {
    private String username; // 用户名 模糊查询
    private Integer status; // 状态 0禁用 1正常
    private String phone; // 手机号
    private LocalDateTime startTime; // 创建时间-开始
    private LocalDateTime endTime; // 创建时间-结束
    private Integer pageNum;
    private Integer pageSize;
    }

    3) Mapper.xml 动态 SQL(标准写法)

    <select id=\”selectUserList\” resultType=\”com.entity.User\”>
    SELECT id, username, phone, status, create_time
    FROM t_user
    <!– 自动拼接 WHERE,剔除第一个多余 AND –>
    <where>
    <!– 用户名模糊查询:非空才拼接 –>
    <if test=\”username != null and username != \’\’\”>
    AND username LIKE CONCAT(\’%\’, #{username}, \’%\’)
    </if>
    <!– 状态:非null才拼接(0也是有效值,不能判空串) –>
    <if test=\”status != null\”>
    AND status = #{status}
    </if>
    <if test=\”phone != null and phone != \’\’\”>
    AND phone = #{phone}
    </if>
    <!– 时间范围 –>
    <if test=\”startTime != null\”>
    AND create_time >= #{startTime}
    </if>
    <if test=\”endTime != null\”>
    AND create_time <= #{endTime}
    </if>
    </where>
    <!– 分页 –>
    LIMIT #{pageNum}, #{pageSize}
    </select>

    关键点解析

  • <where> 优势:
    • 所有条件为空时,自动省略 WHERE 关键字,不会语法报错
    • 自动去掉条件最前面多余的 AND
  • 判断区别:
    • 字符串:!= null and != \’\’(空串视为无查询条件)
    • 数值 / 日期:只判 != null(0、0.0 是合法业务值)
  • 模糊查询:用 CONCAT(\’%\’,#{val},\’%\’),不要在 Java 代码拼接 %。

  • 实战场景 2:动态更新(部分字段更新)

    业务:编辑用户,前端只传修改的字段,空字段不更新(避免覆盖原有数据)。

    赞(0)
    未经允许不得转载:171主机测评 » MySQL 动态 SQL 实战
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址