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

MyBatis Plus分页查询踩坑实录:${ew.sqlSegment}与QueryWrapper的正确配合姿势

MyBatis Plus分页查询实战:规避${ew.sqlSegment}的三大典型陷阱

最近在重构一个老项目的分页查询模块时,我连续踩了三个关于MyBatis Plus分页查询的坑。这些坑看似简单,却让团队浪费了整整两天时间排查。本文将分享这些实战经验,特别是如何正确处理${ew.sqlSegment}与QueryWrapper的配合问题。

1. 分页查询的基础配置

在Spring Boot项目中集成MyBatis Plus分页功能,首先需要配置分页插件。这个步骤看似简单,但配置不当会导致后续所有分页查询失效。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

常见配置错误

  • 忘记添加@Configuration注解
  • 没有指定正确的数据库类型(DbType)
  • 在多个数据源环境下未正确配置分页拦截器

2. ${ew.sqlSegment}的三种典型误用场景

2.1 XML中的条件拼接问题

最常见的错误是在XML映射文件中错误地使用${ew.sqlSegment}。下面是一个典型的错误示例:

<select id="selectPage" resultType="com.example.entity.User"> SELECT * FROM user WHERE 1=1 ${ew.sqlSegment} </select>

这种写法会导致SQL注入风险,且当QueryWrapper为空时会产生语法错误。正确的做法应该是:

<select id="selectPage" resultType="com.example.entity.User"> SELECT * FROM user <where> ${ew.sqlSegment} </where> </select>

2.2 排序条件丢失问题

很多开发者发现分页查询时排序条件不生效,这是因为没有正确处理排序参数的传递。服务层应该这样构建QueryWrapper:

public IPage<User> queryUsers(UserQuery query, Pageable pageable) { QueryWrapper<User> wrapper = new QueryWrapper<>(); // 条件构建 if (StringUtils.isNotBlank(query.getName())) { wrapper.like("name", query.getName()); } // 排序处理 if (pageable.getSort().isSorted()) { pageable.getSort().forEach(order -> { wrapper.orderBy(true, order.isAscending(), order.getProperty()); }); } return userMapper.selectPage(new Page<>(pageable.getPageNumber(), pageable.getPageSize()), wrapper); }

2.3 分页总数计算异常

当使用自定义SQL配合${ew.sqlSegment}时,可能会遇到分页总数计算不正确的问题。这是因为MyBatis Plus的自动分页优化在某些场景下会失效。解决方案是:

@Select("SELECT * FROM user ${ew.customSqlSegment}") IPage<User> selectUserPage(IPage<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);

关键区别

  • ${ew.sqlSegment}包含WHERE关键字
  • ${ew.customSqlSegment}不包含WHERE关键字

3. 性能优化与最佳实践

3.1 避免N+1查询问题

在分页查询中关联其他表时,要特别注意避免N+1查询问题。MyBatis Plus提供了@TableField注解来处理简单关联:

public class User { @TableField(exist = false) private List<Role> roles; }

对于复杂关联,建议使用JOIN查询:

<select id="selectUserWithRoles" resultMap="userWithRoles"> SELECT u.*, r.id as role_id, r.name as role_name FROM user u LEFT JOIN user_role ur ON u.id = ur.user_id LEFT JOIN role r ON ur.role_id = r.id <where> ${ew.sqlSegment} </where> </select>

3.2 分页查询的缓存策略

对于高频访问的分页接口,合理的缓存策略可以显著提升性能:

@Cacheable(value = "userPage", key = "#query.toString() + '-' + #pageable.pageNumber + '-' + #pageable.pageSize") public Page<User> getUsers(UserQuery query, Pageable pageable) { // 分页查询逻辑 }

缓存注意事项

  • 确保查询条件实现了正确的toString()方法
  • 对于实时性要求高的数据,设置较短的缓存时间
  • 在数据修改时及时清除相关缓存

4. 复杂查询场景解决方案

4.1 多表联合分页查询

当需要跨多表进行分页查询时,直接使用MyBatis Plus的分页功能可能会遇到问题。这时可以采用子查询方案:

<select id="selectComplexPage" resultType="com.example.vo.UserVO"> SELECT u.*, d.department_name FROM user u JOIN ( SELECT id FROM user <where> ${ew.sqlSegment} </where> LIMIT #{page.offset}, #{page.size} ) tmp ON u.id = tmp.id JOIN department d ON u.department_id = d.id </select>

4.2 动态字段查询

对于需要动态选择查询字段的场景,可以结合<script>标签实现:

<select id="selectWithDynamicFields" resultType="map"> <script> SELECT <foreach collection="fields" item="field" separator=","> ${field} </foreach> FROM user <where> ${ew.sqlSegment} </where> </script> </select>

对应的Java接口:

IPage<Map<String, Object>> selectWithDynamicFields( IPage<?> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper, @Param("fields") List<String> fields );

在实际项目中,分页查询的复杂性往往超出预期。经过多次迭代,我们总结出一套相对稳定的分页查询工具类,能够处理90%以上的业务场景。

http://www.cnnetsun.cn/news/2162713.html

相关文章:

  • 终极指南:3步快速解密QQ音乐QMC文件,实现音乐自由播放
  • 从鸟群觅食到代码优化:用粒子群算法(PSO)解决你的工程问题,附Python/Matlab对比
  • 从L0原始日志到L4业务语义审计:Dify 2026全新引入LLM驱动的日志意图解析引擎,支持自然语言反向溯源
  • Ministral 3模型:高效密集语言模型的级联蒸馏技术
  • 终极指南:3分钟免费解锁QQ音乐加密文件,让音乐自由播放
  • 告别Pandas卡顿:用PyArrow处理百万行CSV文件,5分钟搞定内存优化
  • 终极指南:如何在Windows电脑上直接安装APK文件?5个简单步骤实现安卓应用无缝运行
  • 使用Python快速编写调用Taotoken多模型API的脚本示例
  • 新手必看!BUUCTF Misc入门实战:从Wireshark到Stegsolve的10个常见套路拆解
  • MATLAB实战:手把手教你用SMI和LSMI波束形成算法抑制干扰(附完整代码)
  • 各种类型玻璃的 K 值、g 值等光热参数汇总表
  • 3C数码电商短视频难在哪?功能演示视频的AI批量生产方案来了
  • 通过taotoken cli一键配置多款ai工具开发环境
  • 【2026年最新600套毕设项目分享】微信小程序自助点餐系统(30210)
  • 【必收藏】2026年大模型应用开发工程师详解!程序员/小白必看,高薪破局就靠它
  • 使用 TaoToken CLI 工具一键配置团队开发环境与模型端点
  • 为什么选择开源纯净小说阅读器?3大理由让你告别广告干扰
  • 【Kubernetes PDB 主动驱逐保护】3 个配置陷阱与正确避坑指南
  • 项目介绍 基于Python的个性化餐饮场所推荐平台设计与实现(含模型描述及部分示例代码)专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
  • Dify工业知识库检索突然失效?排查顺序必须是:① OPC UA时间戳时区偏移 ② PDF扫描件OCR置信度阈值 ③ 领域术语同义词映射表——某汽车焊装车间真实故障链复盘
  • 关于使用锁的沉淀信息量
  • AI 时代下 BI 工具的进化:FineBI 对话式 BI 如何让数据分析人人可用?
  • 抖音无水印下载器:从零到精通的完整指南
  • 手机号逆向查询QQ号:3分钟快速找回遗忘账号的完整方案
  • 手把手教你复现GitLab CVE-2023-7028漏洞(附Burp Suite抓包实战截图)
  • Kubernetes智能运维新范式:kube-copilot如何用AI大语言模型革新kubectl体验
  • Verification安全验证指南:论文AIGC检测高效过关方案
  • Cesium-Wind终极指南:3步快速创建动态3D风场可视化
  • IntelliJ IDEA HTTP Client隐藏技巧:用脚本和动态变量让你的接口测试自动化起来
  • 通过 curl 命令快速测试 Taotoken 的 OpenAI 兼容接口是否通畅