在mybatis中,在列表分页查询过程中造成集合属性数据丢失的问题

在多表关联分页查询中,若集合属性数据跨越分页边界,会导致数据不完整。建议通过对象ID单独查询集合属性,避免分页条件影响,确保数据完整性。

  由于在进行多表关联分页查询时,某一个集合属性的多条数据正好位于2页的分割处,那么就会造成在前一页获取到的该集合属性的集合内部数据不全,因为其余数据被分到了第二页,

因此建议在进行集合属性的封装时,最好是获取到当前对象的id并根据该id进行单独的多表关联查询,不再加上分页的条件,因为这样获取的数据也比较少.从而解决分页带来的集合属性数据丢失的问题.

转载于:https://www.cnblogs.com/tabchanj/p/5721043.html

<think>我们正在讨论PageHelper页插件的使用,特别是如何使用Page类实现分页查询功能。根据引用内容,我们可以总结出以下关键点:1.在RuoYi框架中,通常使用`PageUtils.startPage()`方法来启动页,该方法内部调用了PageHelper的`startPage`方法。2.Mapper接口的返回类型可以是`Page<T>`(推荐)或`List<T>`(不推荐),但即使返回`List<T>`,PageHelper也能通过拦截器实现页。3.页信息可以通过`PageInfo`对象来获取,包括总记录数等。现在,针对用户的问题“我想使用Page类实现分页查询功能,请问Page类分页查询实现方法使用示例”,我们将给出详细步骤示例代码。###使用Page类实现分页查询的步骤1.**引入依赖**:确保项目中已经引入PageHelper的依赖(如Maven依赖)。2.**在Service层启动页**:在调用Mapper方法前,使用`PageHelper.startPage`方法设置页参数(当前页码每页记录数)。3.**执行查询**:调用Mapper的查询方法,此时返回的可以是`Page<E>`类型(实际上`Page<E>`是`ArrayList<E>`的子类,包含了页信息)。4.**封装页信息**:将查询结果转换为`PageInfo`对象,以便获取更丰富的页信息(如总页数、总记录数等)。5.**返回结果**:将页数据返回给前端。###示例代码####1.Mapper接口```java//返回类型为Page<YourEntity>,也可以使用List<YourEntity>,但推荐PagePage<YourEntity>selectYourEntityList(YourEntityparam);```####2.XML映射文件```xml<selectid="selectYourEntityList"resultType="YourEntity">select*fromyour_tablewhere...<!--你的查询条件--></select>```####3.Service层实现```javapublicTableDataInfogetYourEntityList(YourEntityparam){//启动页:参数1为当前页码,参数2为每页记录数PageHelper.startPage(param.getPageNum(),param.getPageSize());//调用Mapper查询,返回Page类型Page<YourEntity>page=yourEntityMapper.selectYourEntityList(param);//使用PageInfo包装结果,PageInfo包含了页的详细信息PageInfo<YourEntity>pageInfo=newPageInfo<>(page);//构建返回对象(RuoYi中使用TableDataInfo作为标准返回格式)returnTableDataInfo.build(pageInfo);}```####4.Controller层调用```java@GetMapping("/list")publicTableDataInfolist(YourEntityparam){returnyourEntityService.getYourEntityList(param);}```###说明-**`PageHelper.startPage`**:必须在执行查询**之前**调用,它使用ThreadLocal保存页参数,然后会被PageHelper的拦截器使用。-**返回类型为`Page<YourEntity>`**:这样可以直接从返回的Page对象中获取页信息(如总记录数),但注意,实际上分页查询会执行两次SQL(次查数据,次查总数)。如果返回`List<YourEntity>`,则需要在查询后使用`PageInfo`来获取页信息。-**`PageInfo`**:是PageHelper提供的个包含完整页信息的类,包括当前页、每页数量、总页数、总记录数、数据列表等。###注意事项-**避免在Service层中新建List**:如果在Service层中先获取了`List<YourEntity>`,然后基于这个List再创建个新的List(例如`newArrayList<>(list)`),那么页信息就会丢失。因为页信息是存储在`Page`对象中的,而普通的List不包含这些信息。-**线程安全**:`PageHelper.startPage()`方法使用了ThreadLocal,所以它必须确保在同个线程中执行,且在查询之后立即使用页信息。在异步或多线程环境下需要特别注意。###相关问题1.如何避免页插件的线程安全问题?2.当查询结果集很大时,PageHelper页性能如何优化?3.除了PageHelper,还有哪些常用的Java页解决方案?</think>### Page类分页查询实现方法与示例 #### 、核心实现原理 1. **页拦截机制** PageHelper 通过 MyBatis 拦截器在 SQL 执行前自动添加页语句(如 MySQL 的 `LIMIT`)[^1]。 2. **线程本地存储** 使用 `ThreadLocal` 存储页参数(页码 pageNum、页大小 pageSize),确保线程安全[^1]。 3. **Page 对象封装** 查询结果自动封装到 `Page<T>` 对象中,包含数据列表页信息(总记录数 total 等)[^1]。 #### 二、完整实现步骤(基于 RuoYi 框架) ##### 1. 添加 Maven 依赖 ```xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.6</version> </dependency> ``` ##### 2. Service 层实现 ```java public TableDataInfo selectUserPage(User user, int pageNum, int pageSize) { // 1. 启动页(必须在Mapper查询前调用) PageHelper.startPage(pageNum, pageSize); // 2. 执行查询(返回Page类型) Page<User> page = userMapper.selectUserList(user); // 3. 封装页数据 return PageUtils.build(page); } ``` ##### 3. Mapper 接口 ```java // 返回Page类型(关键!) Page<User> selectUserList(@Param("user") User user); ``` ##### 4. XML 映射文件 ```xml <select id="selectUserList" resultType="User"> SELECT * FROM sys_user WHERE <if test="user.username != null">username LIKE CONCAT('%', #{user.username}, '%')</if> <!-- 其他条件 --> </select> ``` ##### 5. Controller 层 ```java @GetMapping("/list") public TableDataInfo list(User user, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { return userService.selectUserPage(user, pageNum, pageSize); } ``` #### 三、关键注意事项 1. **返回类型必须为 `Page<T>`** ```java // ✅ 正确:Page<User> Page<User> selectUserList(); // ❌ 错误:List<User> 会丢失页信息 ``` 2. **避免 Service 层新建集合** ```java // ❌ 错误做法(页信息丢失) public TableDataInfo errorExample() { PageHelper.startPage(1, 10); List<User> list = userMapper.selectUserList(); // 返回List return PageUtils.build(new PageInfo(list)); // 需要额外转换 } ``` 3. **标准返回格式 `TableDataInfo`** RuoYi 的标准响应结构: ```json { "code": 200, "msg": "操作成功", "rows": [ /* 数据列表 */ ], "total": 100 // 总记录数 } ``` #### 四、PageUtils 工具类解析 RuoYi 封装的转换方法: ```java public class PageUtils { public static <T> TableDataInfo build(Page<T> page) { TableDataInfo rspData = new TableDataInfo(); rspData.setCode(HttpStatus.SUCCESS); rspData.setRows(page.getResult()); // 当前页数据 rspData.setMsg("查询成功"); rspData.setTotal(page.getTotal()); // 总记录数 return rspData; } } ``` #### 五、执行流程说明 1. `PageHelper.startPage()` 设置线程局部变量 2. Mapper 返回 `Page<User>` 对象 3. 拦截器自动完成: - 执行 `COUNT` 查询获取 total - 修改原 SQL 添加页语句 4. 结果注入 `Page` 对象的 `result` `total` 属性[^1] > ⚠️ **重要**:页操作必须紧邻 Mapper 调用,中间不能插入其他数据库查询。 #### 六、自定义排序支持 ```java PageHelper.startPage(pageNum, pageSize, "create_time DESC"); // 会生成 ORDER BY create_time DESC ``` --- ### 相关问题 1. **如何解决 PageHelper 页后 total 为 -1 的问题?** > 通常因返回类型错误(应为 `Page<T>` 而非 `List<T>`)或线程局部变量被污染导致。 2. **多表关联查询时页失效怎么办?** > 需在 SQL 中使用 `DISTINCT` 或子查询,避免 `COUNT` 语句错误统计。 3. **PageHelper 与 MyBatis-Plus 的页方案如何选择?** > PageHelper 更轻量,MyBatis-Plus 提供更深度集成,根据项目复杂度决策。 4. **如何实现前端页参数自动绑定?** > 使用 `@RequestParam(defaultValue)` 设置默认值,或继承 `PageRequest` 对象封装参数。 [^1]: RuoYi 中使用 PageUtils.startPage() 实现分页查询的完整解析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值