SQL过长应按任务、执行单元和语义逻辑拆分:IN查询分片处理,批量插入用BatchExecutor分批提交,复杂关联改为主查+关联查,XML冗余用<sql>标签抽取共用片段。

SQL 语句太长,通常不是因为写得“啰嗦”,而是因为 IN 列表过大、多表 JOIN 字段过多、动态条件堆叠 或 批量插入语句含成百上千条 VALUES。硬切 SQL 字符串会破坏语法,必须从数据结构和执行逻辑层面拆分。核心思路是:**让单次 SQL 保持安全长度,把大任务拆成多个小任务并行或串行执行**。
IN 查询超长:用 List 分片 + 循环查询
当传入的 ID 列表(如 userIds = [1,2,...,5000])导致 IN 子句过长(MySQL 默认 max_allowed_packet 限制约 4MB),不能靠调大数据库参数治本,应主动分片:
- 用工具类将原始 List 拆成每批 500~1000 个元素的小 List(推荐 Guava 的
Lists.partition(list, 500)或 Hutool 的CollUtil.split()) - Mapper 接口方法保持单参数接收 List,XML 中仍用
<foreach>生成 IN 语句 - Service 层循环调用该方法,合并结果(如
stream().flatMap(Collection::stream).collect())
批量 INSERT 超长:改用 BatchExecutor + 分批提交
一条含 5000 行 VALUES 的 INSERT 语句极易触发 MySQL 报错。MyBatis 原生支持批量,关键在配置和调用方式:
- SqlSessionFactory 配置中设置
executorType="BATCH" - MappedStatement 对应的 XML 保持标准
<insert>,不手动拼 VALUES;由 Java 侧循环调用mapper.insert(item) - 每 1000 条左右手动
sqlSession.flushStatements()提交一次,避免内存溢出
复杂关联查询太长:拆成主查 + 关联查(N+1 优化版)
比如“查 100 个用户 + 每人最新 3 条订单”,若用单条 LEFT JOIN + 子查询,SQL 易膨胀且难以缓存。更稳的做法是:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 第一步:用简洁 SQL 查出用户列表(
SELECT id, name FROM user WHERE ... LIMIT 100) - 第二步:提取所有 user_id,分片后调用另一个 mapper 方法查订单(
select * from order where user_id in (...) order by create_time desc limit 3) - Java 层用 Map<Long, List<Order>> 关联组装,逻辑清晰、SQL 简短、可缓存
XML 冗余重复:用 <sql> + <include> 抽取共用片段
不是物理拆分 SQL,而是消除“看起来长”的假象。例如多处用到相同字段列表或 WHERE 条件:
- 在映射文件顶部定义:
<sql id="userColumns">id as user_id, name as user_name, email</sql> - 在各
<select>中引用:<include refid="userColumns"/> - 同样适用于常用 WHERE 片段(如状态过滤、时间范围),避免重复书写和出错
真正有效的拆分,从来不是切字符串,而是按数据边界切任务、按执行单元切调用、按语义逻辑切结构。MyBatis 给了你控制权,也要求你承担设计责任。

















