前言:
最近小组给了需求,让写一个类似微博的系统,提高我们的开发能力和合作水平,但是里面的分页学长建议自己手写,并未用到分页插件,现在项目结束了,要改进一下,改用PageHelper插件来实现分页功能。
一、Mybatis分页查询的原理
MyBatis是一种Java持久层框架,用于简化与数据库的交互操作。在MyBatis中进行分页查询是常见的需求,MyBatis 分页查询的底层实现原理主要涉及两个方面:SQL 语句的拼接和数据库的分页查询。
1.在 MyBatis 中,我们可以通过在 SQL 语句中添加 LIMIT 或 OFFSET 语句来实现分页查询。LIMIT 用于限制返回的记录数量,OFFSET 则用于指定返回记录的起始位置。因此,我们只需要在 SQL 语句中添加这两个语句,就可以轻松地实现分页查询。如下:
方法一:SELECT * FROM your_table LIMIT #{pageSize} OFFSET #{offset}
方法二:SELECT * FROM your_table LIMIT #{offset},#{pageSize}
2.但是,在实际应用中,分页查询往往需要我们动态地生成 SQL 语句。MyBatis 提供了两种方式来实现动态 SQL 语句的生成:一种是使用 XML 配置文件中的 SQL 片段和动态 SQL 标签;另一种是使用注解。
3.当进行分页查询时,MyBatis 会根据传入的参数计算出需要返回的记录的数量和起始位置,并将这些信息封装成一个 Page 对象传递给底层的数据库查询引擎。数据库引擎则根据传入的 Page 对象进行分页查询,并返回相应的结果集。
4.因此,MyBatis 分页查询的底层实现原理可以概括为:根据传入的参数动态生成带有 LIMIT 和 OFFSET 的 SQL 语句,然后将生成的 SQL 语句传递给底层的数据库引擎进行查询,最终返回分页查询结果。
二、pageHelper分页插件的使用
springboot集成PageHelper分页插件:
1.导入依赖
<!-- ********************** 分页 Pom依赖 ********************** -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
2.在springboot的配置文件里面配置相应的参数(application.properties格式)
pagehelper.helper-dialect=mysql #mysql方言
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
3.使用实例:
方法一:返回PageInfo
ServiceImpl;
@Override
public PageInfo<User> testPageHelper(Integer pageNo, Integer pageSize) {
PageHelper.startPage(pageNo, pageSize);
List<User> userList = blogMapper.test();//调用mapper
PageInfo<User> pageInfo = new PageInfo<>(userList);
return pageInfo;
}
Test:(获取到pageInfo对象,可以获取有关分页的信息)
@Test
public void test() {
PageInfo<User> pageInfo = blogService.testPageHelper(1, 10);
System.out.println(pageInfo.getPages());//总的页数
System.out.println(pageInfo.getTotal());//总的记录数
System.out.println(pageInfo);
}
方法二:返回PageBean
PageBean实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "PageBean对象:分页实体类",description = "分页实体类")
public class PageBean {
@ApiModelProperty(value = "总的记录数", name = "total")
private Long total;
@ApiModelProperty(value = "每页的数据,一个个对象", name = "rows")
private List rows;
}
ServiceImpl:
@Override
public PageBean testPageHelper(Integer pageNo, Integer pageSize) {
PageHelper.startPage(pageNo, pageSize);
List<User> userList = blogMapper.test();
Page<User> page = (Page<User>) userList;
return new PageBean(page.getTotal(),page.getResult());
}
test:
@Test
public void test() {
PageBean pageBean = blogService.testPageHelper(1, 10);
System.out.println(pageBean);
}
注意,必须是调用查询方法之前就使用PageHelper.startPage,中间不能有其它的查询操作。因为PageHelper.startPage采用的是ThreadLocalL保存分页参数,然后在执行查询数据库sql时,通过拦截器PageInterceptor在sql语句中添加了分页参数,达到分页的目的,执行新的sql获取分页结果,最后在finally方法中清空ThreadLocalL。
所以这里PageHelper有个隐患,如果设置了PageHelper.startPage,之后的查询语句如果出现异常,就导致PageHelper中的ThreadLocalL仍然具有分页参数,如果此时有一个非分页的查询语句进来,这个时候就该查询就会被分页(而本不应该需要分页)。
还有一点,在多数据源的情况下,也要注意pagehelper的使用,默认它只会在一个数据源中起作用。