Mybatis是如何进行分页的?

MyBatis的分页实现主要有以下几种方式:

1. 逻辑分页(RowBounds)

在MyBatis核心包中提供,但存在性能问题:

// 使用RowBounds进行内存分页
List<User> users = sqlSession.selectList(
    "com.example.mapper.UserMapper.selectUsers", 
    null, 
    new RowBounds(0, 10)  // offset, limit
);

缺点:实际查询所有数据到内存后再分页,大数据量时性能差

2. 物理分页(原生SQL)

手动在SQL中编写分页语句:

MySQL

<select id="selectByPage" resultType="User">
    SELECT * FROM user 
    LIMIT #{offset}, #{pageSize}
</select>

Oracle

<select id="selectByPage" resultType="User">
    SELECT * FROM (
        SELECT t.*, ROWNUM rn FROM (
            SELECT * FROM user ORDER BY id
        ) t WHERE ROWNUM <= #{end}
    ) WHERE rn >= #{start}
</select>

3. 分页插件(推荐)

PageHelper(最常用)

<!-- 1. 添加依赖 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.2</version>
</dependency>
// 2. 使用示例
PageHelper.startPage(1, 10);  // 第1页,每页10条
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);

// 获取分页信息
pageInfo.getTotal();     // 总记录数
pageInfo.getPages();     // 总页数
pageInfo.getList();      // 当前页数据

MyBatis-Plus分页

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

// 2. 使用
Page<User> page = new Page<>(1, 10);
IPage<User> userPage = userMapper.selectPage(page, null);

userPage.getTotal();      // 总记录数
userPage.getRecords();    // 分页数据

4. 自定义分页拦截器

可以自己实现Interceptor接口:

@Intercepts(@Signature(type = StatementHandler.class, 
    method = "prepare", args = {Connection.class, Integer.class}))
public class PageInterceptor implements Interceptor {
    // 实现分页逻辑
    // 1. 解析分页参数
    // 2. 重写SQL,添加分页语句
    // 3. 查询总数
}

5. 参数分页

通过Map或PageParam对象传递参数:

public interface UserMapper {
    List<User> selectByPage(@Param("offset") int offset, 
                           @Param("pageSize") int pageSize);
}
<select id="selectByPage" resultType="User">
    SELECT * FROM user
    <if test="offset != null and pageSize != null">
        LIMIT #{offset}, #{pageSize}
    </if>
</select>

最佳实践建议

  1. 中小型项目:推荐使用PageHelper,配置简单,功能丰富
  2. 使用MyBatis-Plus的项目:直接使用其内置分页功能
  3. 需要自定义逻辑:可考虑实现自定义拦截器
  4. 性能要求极高:手动编写优化SQL,使用数据库特定语法

性能对比

分页方式优点缺点适用场景
RowBounds简单易用内存分页,性能差小数据量测试
原生SQL性能最好SQL不通用,维护难对性能要求极高
PageHelper功能全面,易用增加依赖大多数业务场景
MyBatis-Plus无缝集成需全套使用MP使用MP的项目

注意事项

  • 分页时要考虑排序字段的索引优化
  • 深度分页(如第1000页)建议使用游标或搜索优化
  • 分布式环境下注意分页一致性

作 者:南烛
链 接:https://www.itnotes.top/archives/939
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇