使用PageHelper遇到的问题

在mybatis结合PageHelper分页工具使用时,可以节省不少代码与时间,但也有可能碰到一些问题。以下会记录使用时遇到的坑。

(一)在mybatis使用collection映射一对多关系的结果集时,PageInfo返回的total总数错误

错误案例(只贴关键部分代码):

service层:

@Service
public class TeacherService {

    @Resource
    TeacherMapper teacherMapper;

    public PageInfo selectListByPage(PageParam pageParam) {
        PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
        return new PageInfo(teacherMapper.selectListByPage());
    }
}

TeacherMapper.xml文件:





  
    
    
    
    
  

  
    
    
    
    
      
      
      
    
  

    

说明:有对应数据库表结构的Teacher、Class、Student三个实体类,Teacher类与Class类的关系为一对多,Class类与Student类的关系为一对多,所以一个老师拥有多个班级的多个学生。在xml文件里映射一个结果集,然后用sql查出老师对应的班级以及学生的信息(这里定义了三个返回dto实体类)。

直接sql查数据库返回的结果:

使用postman测试接口返回的分页结果:

为了直观,返回数据压缩在一起,我们可以看到,从预想的结果应该是返回的total总数是2条的,因为只有2位老师,但这里分页后返回的却是5条;因为取的是join从表后的全部数据总数,而不是teacher主表的总数,所以会出现total总数错误。

解决办法:

对TeacherMapper.xml改造,使用collection中的select属性,以及先对主表分页,然后根据主表分页查询出的数据再查询从表对应的数据





  
    
    
    
    
  

  
    
    
    
    
    
  

  
    
    
    
  

    

    

    



说明:

  1. 这里collection中不能再使用resultMap属性,应该使用ofType属性;
  2. column属性表示根据哪个字段查询,假如需要根据多个字段查询,比如根据cid和tid查询,可写成column="{cid=cid, tid=tid}",=等号左边指传递查询的参数名称,=等号右边指数据库的字段名称,只有一个参数的时候可以只写传递查询的参数名称;
  3. select属性代表着当执行完selectListByPage后,接着根据第一步得到的tid执行selectClassListByTid,最后再根据第二步得到的cid执行selectStudentListByCid;
  4. 实际中查询班级结果以及学生结果的sql应该放在班级实体以及学生实体的xml文件中,这里为了直观展示全放在老师实体的TeacherMapper.xml中;

但上面的解决办法也会产生一个问题—N+1问题:简单形容就是当从主表(比如teacher表)执行一次查询时,得到N条数据,那么这时从表(比如class表)可能就需要执行N次查询,这样会造成数据库较大的开销。

可以通过设置日志打印,更加直观地看到N+1这个问题:

但其实可以通过设置懒加载机制去解决,这里不作讲解!

所以综上所述,在涉及分页的场景时,个人认为采取原生sql分页的方式最适当,可查看另外一篇文章!

你可能感兴趣的:(MyBatis)