25. MyBatis中的RowBounds是什么?如何实现内存分页?12. 如何在MyBatis中进行分页查询?常见的分页实现方式有哪些?

是 MyBatis 提供的一种用于结果集分页的功能,主要通过内存分页的方式实现。它通过在查询时传递分页参数,限制返回的结果集的大小。RowBounds 并不依赖于数据库层的分页功能,而是通过 MyBatis 在内存中对结果集进行截取,从而实现分页。

 

RowBounds 的基本属性

  • offset:从结果集的第几条记录开始截取。

  • limit:截取的记录条数。

例如,offset=5,limit=10 的 RowBounds 实例表示从结果集的第 6 条记录开始,取 10 条记录。

 

如何在 MyBatis 中使用 RowBounds 实现内存分页?

 

1. 使用 RowBounds 进行内存分页

RowBounds 的使用非常简单,可以通过 SqlSession 的 selectList 方法来传递 RowBounds 实例,从而实现分页。

 

示例:

假设我们有一个数据库表 user,并希望对查询结果进行分页。

Step 1: 定义 Mapper 接口

 
  1. public interface UserMapper {
  2.   List<User> selectAllUsers(RowBounds rowBounds);
  3. }
 

Step 2: 配置 XML 映射文件

 
  1. <mapper namespace="com.example.mapper.UserMapper">
  2.   <select id="selectAllUsers" resultType="User">
  3.       SELECT * FROM user
  4.   </select>
  5. </mapper>
 

Step 3: 使用 RowBounds 实现分页查询

 
  1. try (SqlSession session = sqlSessionFactory.openSession()) {
  2.   UserMapper mapper = session.getMapper(UserMapper.class);
  3. ​
  4.   // 分页参数:从第 10 条记录开始,取 10 条记录
  5.   RowBounds rowBounds = new RowBounds(10, 10);
  6. ​
  7.   List<User> users = mapper.selectAllUsers(rowBounds);
  8. ​
  9.   users.forEach(System.out::println);
  10. }
 

在这个例子中,RowBounds 实例被传递给 selectAllUsers 方法。RowBounds 将从查询结果的第 11 条记录开始,取 10 条记录进行返回。

 

2. RowBounds 的局限性

尽管 RowBounds 实现了分页功能,但它有一些局限性:

  • 内存分页:RowBounds 是在内存中对查询结果进行分页,这意味着在数据库层面,查询仍然会返回完整的结果集。如果结果集非常大(比如包含数百万条记录),则会消耗大量的内存和处理时间,不适用于大数据量分页。

  • 性能问题:由于 RowBounds 是在内存中截取结果集,这对内存和 CPU 的消耗较大,尤其是当 offset 较大时,查询性能会显著下降。

 

如何实现数据库层面的分页(推荐)?

由于 RowBounds 的局限性,通常更推荐在数据库层面进行分页查询。不同的数据库支持不同的分页查询语法,以下是几种常见数据库的分页实现方式。

 

1. MySQL

在 MySQL 中,可以通过 LIMIT 子句实现分页:

 

SELECT * FROM user LIMIT #{offset}, #{limit};

MyBatis 配置:

 
  1. <select id="selectUsersWithPagination" resultType="User">
  2.   SELECT * FROM user LIMIT #{offset}, #{limit}
  3. </select>
 

Mapper 接口:

 
  1. public interface UserMapper {
  2.   List<User> selectUsersWithPagination(@Param("offset") int offset, @Param("limit") int limit);
  3. }
 

调用:

 
  1. try (SqlSession session = sqlSessionFactory.openSession()) {
  2.   UserMapper mapper = session.getMapper(UserMapper.class);
  3.   List<User> users = mapper.selectUsersWithPagination(10, 10);
  4.   users.forEach(System.out::println);
  5. }
 
 

2. Oracle

在 Oracle 中,可以通过 ROWNUM 或者 ROW_NUMBER() 函数实现分页:

 
  1. SELECT * FROM (
  2.   SELECT t.*, ROWNUM r FROM (SELECT * FROM user ORDER BY id) t WHERE ROWNUM <= #{end}
  3. ) WHERE r > #{start};
 

MyBatis 配置:

 
  1. <select id="selectUsersWithPagination" resultType="User">
  2.   SELECT * FROM (
  3.       SELECT t.*, ROWNUM r FROM (SELECT * FROM user ORDER BY id) t WHERE ROWNUM <= #{end}
  4.   ) WHERE r > #{start}
  5. </select>
 

Mapper 接口:

 
  1. public interface UserMapper {
  2.   List<User> selectUsersWithPagination(@Param("start") int start, @Param("end") int end);
  3. }
 

调用:

 
  1. try (SqlSession session = sqlSessionFactory.openSession()) {
  2.   UserMapper mapper = session.getMapper(UserMapper.class);
  3.   List<User> users = mapper.selectUsersWithPagination(10, 20); // 从第11到20条
  4.   users.forEach(System.out::println);
  5. }
 
 

3. PostgreSQL

在 PostgreSQL 中,使用 LIMIT 和 OFFSET 进行分页:

SELECT * FROM user LIMIT #{limit} OFFSET #{offset};

MyBatis 配置和调用方式与 MySQL 类似。

 

总结

  • RowBounds 的用途:RowBounds 是 MyBatis 提供的一种内存分页方式,适用于小数据量的分页场景。

  • 局限性:由于 RowBounds 是在内存中截取结果集,对于大数据量分页会带来性能问题和内存消耗,通常不推荐在大数据量情况下使用。

  • 推荐的分页方式:通常推荐在数据库层面进行分页,通过 SQL 的 LIMIT 或 OFFSET 等子句直接获取分页后的结果集,这样可以有效减少数据传输和内存占用,提高分页性能。

在实际开发中,根据数据量大小和系统性能要求选择合适的分页方式。

 

在MyBatis中,分页查询是一种常见的需求,尤其是在处理大数据量的情况下。MyBatis本身不直接提供分页功能,但可以通过以下几种常见的实现方式来实现分页查询。

 

1. 手动分页

这是最基本的分页方式,直接在SQL语句中添加分页参数。不同的数据库分页语法不同,以下是一些常见数据库的分页实现。

 

1.1 MySQL中的分页

 

 
  1. <select id="findUsersByPage" resultType="User">
  2.   SELECT * FROM users
  3.   LIMIT #{offset}, #{pageSize}
  4. </select>
 
  • LIMIT #{offset}, #{pageSize}:offset表示起始行偏移量,pageSize表示每页的记录数。

 

1.2 Oracle中的分页

 
  1. <select id="findUsersByPage" resultType="User">
  2.   SELECT * FROM (
  3.       SELECT A.*, ROWNUM AS RN
  4.       FROM (SELECT * FROM users ORDER BY id) A
  5.       WHERE ROWNUM <= #{endRow}
  6.   )
  7.   WHERE RN > #{startRow}
  8. </select>
 
  • Oracle使用ROWNUM来实现分页,其中startRow和endRow分别表示分页的起始和结束行号。

 

1.3 SQL Server中的分页

 
  1. <select id="findUsersByPage" resultType="User">
  2.   SELECT * FROM (
  3.       SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNum, *
  4.       FROM users
  5.   ) AS result
  6.   WHERE RowNum BETWEEN #{startRow} AND #{endRow}
  7. </select>
 
  • SQL Server中,使用ROW_NUMBER()函数进行分页,并结合BETWEEN语句来筛选行号范围。

 

2. 使用RowBounds对象进行分页

MyBatis提供了RowBounds对象用于内存分页。它会将查询结果集限制在指定的行数内。这种方式不依赖于数据库的分页语法,而是通过Java内存进行分页。

 

2.1 使用RowBounds分页

 
  1. List<User> findUsers(RowBounds rowBounds);
  2. java复制代码RowBounds rowBounds = new RowBounds(offset, pageSize);
  3. List<User> users = userMapper.findUsers(rowBounds);
 
  • RowBounds通过offset和limit进行分页。

 

2.2 注意事项

  • RowBounds会将查询的所有结果集加载到内存中,然后进行分页处理,这对大数据量查询效率较低,适合小数据量分页场景。

 

3. 使用分页插件

分页插件是一种更为高效和方便的方式,特别是在大型项目中。分页插件会自动拦截查询SQL,并在其基础上增加分页逻辑。

 

3.1 MyBatis-PageHelper插件

PageHelper是MyBatis的一个常用分页插件,它通过拦截SQL语句并追加分页语句来实现分页查询。

  • Maven依赖:

     
    1. <dependency>
    2.   <groupId>com.github.pagehelper</groupId>
    3.   <artifactId>pagehelper</artifactId>
    4.   <version>5.2.0</version>
    5. </dependency>
     
  • 配置方式:

     
    1. @Configuration
    2. public class MyBatisConfig {
    3.   @Bean
    4.   public PageHelper pageHelper() {
    5.       PageHelper pageHelper = new PageHelper();
    6.       Properties properties = new Properties();
    7.       properties.setProperty("helperDialect", "mysql");
    8.       properties.setProperty("reasonable", "true");
    9.       properties.setProperty("supportMethodsArguments", "true");
    10.       pageHelper.setProperties(properties);
    11.       return pageHelper;
    12.   }
    13. }
     
  • 使用方式:

     
    1. PageHelper.startPage(pageNum, pageSize);
    2. List<User> users = userMapper.findAll();
    3. PageInfo<User> pageInfo = new PageInfo<>(users);
     
    • PageHelper.startPage(pageNum, pageSize):设置分页参数,pageNum表示当前页码,pageSize表示每页显示的记录数。

    • PageInfo<User>:PageInfo是一个分页结果对象,包含了分页后的信息,如总页数、总记录数等。

 

3.2 MyBatis-Plus中的分页插件

MyBatis-Plus也提供了分页插件,使用方式类似于PageHelper。

  • Maven依赖:

     
    1. <dependency>
    2.   <groupId>com.baomidou</groupId>
    3.   <artifactId>mybatis-plus-boot-starter</artifactId>
    4.   <version>3.4.3.4</version>
    5. </dependency>
     
  • 配置方式:

     
    1. @Configuration
    2. public class MyBatisPlusConfig {
    3.   @Bean
    4.   public MybatisPlusInterceptor mybatisPlusInterceptor() {
    5.       MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    6.       interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    7.       return interceptor;
    8.   }
    9. }
     
  • 使用方式:

     
    1. Page<User> page = new Page<>(pageNum, pageSize);
    2. IPage<User> userPage = userMapper.selectPage(page, null);
     
    • Page<>(pageNum, pageSize):构建分页参数对象。

    • IPage<User>:MyBatis-Plus中的分页结果对象,包含分页后的数据和分页信息。

 

4. 数据库支持的分页查询

有些数据库(如MySQL、PostgreSQL)天生支持分页查询,可以直接在SQL语句中使用LIMIT、OFFSET等关键字进行分页,而其他数据库(如Oracle)则需要使用子查询或窗口函数来实现分页。

 

总结

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

  1. 手动分页:直接在SQL中编写分页语句,适合于需要控制分页SQL的场景,但需要根据不同数据库编写不同的分页SQL。

  2. RowBounds分页:MyBatis提供的内存分页方法,适合小数据量分页,但不推荐大数据量使用。

  3. 分页插件:如PageHelper、MyBatis-Plus分页插件,通过拦截器方式实现分页,自动生成分页SQL,适合大多数场景,性能较好。

选择哪种分页方式应根据项目的实际需求、数据量大小以及开发的复杂性进行权衡。对于大多数场景,使用分页插件是一个简单高效的选择。

 

posted @ 2025-01-03 11:17  charyGao  阅读(141)  评论(0)    收藏  举报