MyBatis 分页插件开发
PageHelper 内部到底怎么实现的?手写一个 MyBatis 分页插件,深入理解插件拦截机制。
一、MyBatis 插件的拦截原理
- 1.1 可拦截的四大对象——Executor / ParameterHandler / StatementHandler / ResultSetHandler
- 1.2 拦截哪个对象决定插件的功能——分页插件拦截 Executor 或 StatementHandler
- 1.3
Plugin.wrap()动态代理的实现
二、分页插件设计思路
- 2.1 拦截点选择——
Executor.query()还是StatementHandler.prepare() - 2.2 PageHelper 的思路——拦截 Executor
- 2.3 自定义插件的思路——拦截 StatementHandler
三、拦截 StatementHandler 实现分页
- 3.1 获取原始 SQL——
BoundSql.getSql() - 3.2 拼接 count SQL——
SELECT COUNT(*) FROM (原SQL) _count - 3.3 拼接分页 SQL——
LIMIT offset, pageSize - 3.4 反射修改
StatementHandler中的BoundSql - 3.5 设置分页参数——Page 对象的 ThreadLocal 传递
四、拦截 Executor 实现分页
- 4.1 拦截
Executor.query(MappedStatement, Object, RowBounds, ResultHandler) - 4.2 修改 MappedStatement 中的 SQL
- 4.3 这种方式的优势——可以同时获取 count 和 list
五、完整插件代码
- 5.1 注解配置——
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})) - 5.2
intercept()方法的核心逻辑 - 5.3
Dialect接口——适配不同数据库(MySQL / PostgreSQL / Oracle)
六、测试验证
- 6.1 配置插件——
mybatis-config.xml或 Spring Boot 配置 - 6.2 测试分页查询——验证 SQL 改写和执行结果
- 6.3 性能对比——与 PageHelper 的性能差异
七、总结
- 插件的核心是”拦截 + 增强”
- 编写插件的注意事项——ThreadLocal 清理、性能考量
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 谜思录!