总结一下:分页的几种办法
以mysql为例,做分页的方法,目前我总结了3种。
第一种分页:采用Query类和PageUtils类做出分页,sql用limit获取条数
第一步:Query 类的作用是对传入的分页参数做处理,并计算出当前页的起始和结束条数
@Data
public class Query extends LinkedHashMap<String, Object> {
private static final long serialVersionUID = 1L;
private int page;
private int limit;
public Query(Map<String, Object> params){
this.putAll(params);
this.page = Integer.parseInt(params.get("page").toString());
this.limit = Integer.parseInt(params.get("limit").toString());
this.put("offset", (page - 1) * limit);
this.put("page", page);
this.put("limit", limit);
}
}
第二步:根据查询的结果计算总页数
@Data
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
private int totalCount;
private int pageSize;
private int totalPage;
private int currPage;
private List<?> list;
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
}
第三步: java代码中使用分页
Query query = new Query(params);
List<Bug> list = bugService.queryList(query);
int total = bugService.queryTotal(query);
PageUtils pageUtil = new PageUtils(list, total, query.getLimit(), query.getPage());
return R.ok().put("page", pageUtil).put("total", total);
查询sql的写法:
<if test="offset != null and limit != null">
limit
</if>
这个方法简单明了,接近原生,更好理解原理,缺点是代码多,要单独查总记录数
第二种分页:采用插件pagehelper(前面博客有讲,这里简单过一下)
第一步:导包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
第二步:配置yml
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
第三步:分页(只列出关键代码)
int start = Integer.parseInt(String.valueOf(map.get("start")));
int limit = Integer.parseInt(String.valueOf(map.get("limit")));
PageHelper.startPage(start,limit);
PageInfo<HonorEntity> pageInfo = new PageInfo<>(pageHelperServiceImpl.pageHonor());
这样查出来的代码分页的参数齐全的。
不需要单独查总数,简单易用。
注意:
使用spring boot2整合 pagehelper-spring-boot-starter必须排除一下依赖
因为pagehelper-spring-boot-starter也已经在pom依赖了mybatis与mybatis-spring
所以会与mybatis-plus-boot-starter中的mybatis与mybatis-spring发生冲突
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
深坑再现: 最近遇到使用pageHelper总数不正确的问题,总是随前端传的分页参数变化而变化。原因是:
在 PageInfo<HonorEntity> pageInfo = new PageInfo<>(pageHelperServiceImpl.pageHonor());
pageInfo
中的数据又做了流式数据处理导致获取到的list的size.(比如这里的a就是真实去数据库查询的list集合)
参看pageHelper的底层:PageSerializable类的构造
public PageSerializable(List list) {
this.list = list;
if (list instanceof Page) {
this.total = ((Page)list).getTotal();
} else {
this.total = (long)list.size();
}
}
即:本来pageInfo 是Page类型,里面封装了total,如果做了其他处理就成了List类型即,total
获取到的是list的大小了。
第三种:mybatis-plus自带的分页
在项目使用mybatis-plus时使用它自己的分页即可。
第一步:导入mybatis-plus的包(以后项目尽量都导它,因为它和mybatis兼容的,用不用都可以)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>
第二步:写一个关于分页的配置类(只有中间那个paginationInterceptor是关于分页的,这里是官网写法,最简单就是直接返回对象,其他都不用配置)
@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1000);
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
第三步:代码中的使用(这里是在实现类调用dao层的方法)
public R pageNationQuery(int start,int limit) {
IPage<LiaochaoUser> page = new Page<>(start,limit);
page = liaochaoUserMapper.selectPage(page, null);
return R.ok("查询成功").put("data",page);
}
总结:
三种方法都可以,都不错,第一种虽然代码多但是它轻量啊,群智曾使用。
第二种,方便简单,当初傻傻找查总记录数是哪个sql,始终找不到,联通曾使用。
第三种是以后的趋势,是mybatis-plus的附属功能,网络态势项目使用。
高效查询是否存在和高效分页
1、查询是否存在还在用count(*)吗? out了!
count(0)
:将返回表格中所有存在的行的总数包括值为null的行 count(1)
:会统计包括null值的所有符合条件的字段的条数。
count(0)count(1) count(*
) 都会返回null的行
count(字段)
:将返回表格中除去null以外的所有行的总数(有默认值的列也会被计入)
按效率排序的话,count(字段)<count(主键 id)<count(1)≈count(*)
高效查询是否存在:
SELECT 1 FROM sys_user WHERE id = 1000009 LIMIT 1
SQL不再使用count,而是改用LIMIT 1,让数据库查询时遇到一条就返回,不要再继续查找还有多少条了
业务代码中直接判断是否非空即可,存在会返回1,不存在会返回null
2、高效分页
传统分页:select * from table limit 10000,10;
偏移量越大则越慢
推荐分页:select * from table WHERE id>=23434 limit 11;
limit #{offset}, #{limit}后的两个参数是:
#{offset}起始页,它是从0开始的,第一页就是取0
#{limit}每页条数
如果只查询前几条的话,分页参数只需要一个即可
例如:select * from t_user limit 5
它代表查询表中前5条
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)