MyBatis-Plus的分页原理是什么?

1 个回答

  • 小王子-B152
    不妨大胆一点,很多事情都没有答案。
    MyBatis-Plus 支持通过分页插件实现分页查询,核心是 **`PaginationInnerInterceptor`** 插件,该插件通过拦截 SQL 请求,自动计算分页参数并在 SQL 中添加 `LIMIT` 子句来实现分页。 以下是 MyBatis-Plus 分页的详细工作原理和使用方法: ### **1. 分页原理** #### **1.1 分页方式** - **物理分页**: - MyBatis-Plus 使用物理分页方式,通过在 SQL 中加入 `LIMIT` 子句来控制查询的起始位置和返回记录数。 - **优点**: - 减少数据库内存占用。 - 减轻数据库负载,提升查询效率。 - **缺点**: - 无法对结果进行额外操作,例如分页后再做二次过滤或复杂的字段映射。 #### **1.2 核心分页拦截器** 分页功能由 `PaginationInnerInterceptor` 实现。它的作用是拦截所有 SQL 查询请求,并在 SQL 中动态拼接分页条件。 **拦截器的关键流程:** 1. **拦截 SQL**: - 在执行 SQL 查询前拦截请求,并判断是否需要分页。 2. **计算分页参数**: - 根据 `Page` 对象中的 `currentPage` 和 `pageSize` 参数,计算分页的起始位置 (`offset`) 和返回记录数 (`limit`)。 3. **拼接分页 SQL**: - 在原始 SQL 末尾添加 `LIMIT` 子句。例如: ```sql SELECT * FROM user LIMIT 10, 20 ``` 上述 SQL 表示从第 10 条记录开始,返回 20 条记录。 4. **执行分页查询**: - 修改后的 SQL 被发送到数据库执行,返回分页结果。 #### **核心方法** `PaginationInnerInterceptor` 的分页逻辑主要在 `beforeQuery` 方法中完成: ```java @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 核心:检查分页参数并生成分页 SQL String paginationSql = buildPaginationSql(originalSql, offset, limit); // 将分页 SQL 替换到 BoundSql 中 metaObject.setValue("delegate.boundSql.sql", paginationSql); } ``` 其中: - **`buildPaginationSql`**:根据数据库类型生成对应的分页 SQL。例如,MySQL 的实现会添加 `LIMIT ?, ?` 子句。 - **分页参数**:`offset` 表示起始位置,`limit` 表示返回的记录数。 ### **2. 分页插件的使用** #### **2.1 添加分页插件** 在 MyBatis-Plus 配置中添加 `PaginationInnerInterceptor` 分页插件。 **示例代码**: ```java @Configuration @MapperScan("com.example.mapper") public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件(MySQL 数据库) interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` #### **2.2 编写 Mapper 接口** 使用 MyBatis-Plus 提供的 `BaseMapper` 接口,无需手动编写分页查询 SQL。 **示例代码**: ```java public interface UserMapper extends BaseMapper<User> { // 可以扩展其他自定义方法 } ``` #### **2.3 执行分页查询** 使用 MyBatis-Plus 提供的 `selectPage` 方法完成分页查询。 **示例代码**: ```java @Autowired private UserMapper userMapper; public IPage<User> selectUserPage(int currentPage, int pageSize) { // 创建分页对象 Page<User> page = new Page<>(currentPage, pageSize); // 执行分页查询 return userMapper.selectPage(page, null); // 第二个参数为查询条件,此处为 null 表示无条件查询 } ``` ### **3. 分页结果处理** 分页查询返回的结果是一个 `IPage` 对象,它包含了分页信息和查询结果。 #### **IPage 的常用方法** - **当前页码**:`getCurrent()` - **每页记录数**:`getSize()` - **总记录数**:`getTotal()` - **总页数**:`getPages()` - **记录列表**:`getRecords()` **示例**: ```java IPage<User> userPage = userMapper.selectPage(new Page<>(1, 10), null); System.out.println("当前页码:" + userPage.getCurrent()); System.out.println("每页记录数:" + userPage.getSize()); System.out.println("总记录数:" + userPage.getTotal()); System.out.println("总页数:" + userPage.getPages()); System.out.println("记录列表:" + userPage.getRecords()); ``` ### **4. 分页统计的实现** `PaginationInnerInterceptor` 还会在查询总记录数时,生成一个统计总数的 SQL 并执行。例如: - 原始查询: ```sql SELECT * FROM user LIMIT 10, 20; ``` - 统计总数的 SQL: ```sql SELECT COUNT(*) FROM user; ``` 统计总数的逻辑主要在 `willDoQuery` 方法中实现。 ### **5. 总结** | **特性** | **描述** | |-----------------------|---------------------------------------------------------------------------------------------| | **分页方式** | MyBatis-Plus 采用物理分页,通过 `LIMIT` 子句控制返回的记录范围。 | | **核心插件** | `PaginationInnerInterceptor`,负责拦截查询请求并自动添加分页条件。 | | **实现原理** | - 拦截 SQL 并计算分页参数(`offset` 和 `limit`)。<br>- 动态修改 SQL,拼接 `LIMIT` 子句。 | | **使用步骤** | - 添加分页插件到配置。<br>- 编写 `Mapper` 接口继承 `BaseMapper`。<br>- 调用 `selectPage` 方法查询。| | **分页结果** | 返回 `IPage` 对象,包含分页信息(如总记录数、总页数)和结果列表。 | 通过 `PaginationInnerInterceptor` 插件,MyBatis-Plus 实现了简单、自动的分页功能,大大简化了分页逻辑的开发工作。
    编辑于 2024-11-23 22:27 •IP属地 美国
    举报
    评论
    收藏