Mybatis 您所在的位置:网站首页 分页插件的原理图 Mybatis

Mybatis

2024-06-18 23:25| 来源: 网络整理| 查看: 265

前言

今天使用了分页插件,并将其整合到SpringBoot中。各种遇到了个别问题,现在记录下。吃一垫长一智。

整合 与SpringBoot整合 1. 引入依赖 com.github.pagehelper pagehelper-spring-boot-starter 1.2.5 2. 配置参数

接着在application.yml中配置相关参数

#pagehelper pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql returnPageInfo: check

参数说明 https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

3.使用 #方式1 PageHelper.startPage(1, 10); List goodsCategoryList = mapper.selectByPage(); int totalCount=(int) ((Page)goodsCategoryList).getTotal(); # 方式二 PageHelper.offsetPage(1, 10); List goodsCategoryList = mapper.selectByPage(); PageInfo pageInfo = new PageInfo(goodsCategoryList); int totalCount=(int) pageInfo.getTotal(); 与Spring MVC 整合 1. 引入依赖 com.github.pagehelper pagehelper 最新版本 2. 配置拦截器(这是核心,如果不配置则分页不起作用)

在Spring的配置文件中配置拦截器插件

params=count=countSql helperDialect=mysql reasonable=true supportMethodsArguments=true returnPageInfo=check

配置好之后,使用同上。

原理

其最核心的方法就在拦截器中,那我们首先看看拦截器中的拦截方法。该方法主要做了两件事,1. 统计总条数,2.对原始的SQL进行改写使其可以分页。 PageInterceptor类的intercept方法是拦截器的总入口方法。

1.统计总条数

首先,我们来看看统计总条数的相关代码。

//PageInterceptor 类 //设置count的sql的id,在原始的msId后面加上_COUNT后缀。 String countMsId = msId + countSuffix; // 生成统计sql的入口方法 count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);

接下来我们就来看看executeAutoCount 方法

/** * 执行自动生成的 count 查询 * * @param executor sql执行器 * @param countMs * @param parameter * @param boundSql * @param rowBounds * @param resultHandler 结果处理器 * @return * @throws IllegalAccessException * @throws SQLException */ private Long executeAutoCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException, SQLException { Map additionalParameters = (Map) additionalParametersField.get(boundSql); //创建 count 查询的缓存 key CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql); //调用方言获取 count sql String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey); //countKey.update(countSql); BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter); //当使用动态 SQL 时,可能会产生临时的参数,这些参数需要手动设置到新的 BoundSql 中 for (String key : additionalParameters.keySet()) { countBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } //执行 count 查询 Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); Long count = (Long) ((List) countResultList).get(0); return count; }

如上,方法的注释比较详实,此处我们主要介绍下第二步调用方言获取 count sql。dialect 是一个接口类,PageHelper是其的一个实现类。接着我们来看看PageHelper中的getCountSql方法。

//*PageHelper @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { return autoDialect.getDelegate().getCountSql(ms, boundSql, parameterObject, rowBounds, countKey); }

如上,在PageHelper的getCountSql直接把请求给了AbstractHelperDialect(通过autoDialect.getDelegate() 获得) 的getCountSql 方法。我们接着往下看

//*AbstractHelperDialect @Override public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) { Page page = getLocalPage(); String countColumn = page.getCountColumn(); if (StringUtil.isNotEmpty(countColumn)) { return countSqlParser.getSmartCountSql(boundSql.getSql(), countColumn); } return countSqlParser.getSmartCountSql(boundSql.getSql()); }

如上,countsql语句的生成逻辑最终落在了CountSqlParser类,该类是一个通用的sql解析类。最后我们来看看CountSqlParser类的getSmartCountSql方法。

/** * 获取智能的countSql * * @param sql 我们传入的需要分页的sql * @param name 列名,默认 0 * @return */ public String getSmartCountSql(String sql, String name) { //解析SQL Statement stmt = null; //特殊sql不需要去掉order by时,使用注释前缀 if(sql.indexOf(KEEP_ORDERBY) >= 0){ return getSimpleCountSql(sql); } try { // 对sql 进行分解 stmt = CCJSqlParserUtil.parse(sql); } catch (Throwable e) { //无法解析的用一般方法返回count语句 return getSimpleCountSql(sql); } Select select = (Select) stmt; SelectBody selectBody = select.getSelectBody(); try { //处理body-去order by processSelectBody(selectBody); } catch (Exception e) { //当 sql 包含 group by 时,不去除 order by return getSimpleCountSql(sql); } //处理with-去order by processWithItemsList(select.getWithItemsList()); //处理为count查询 sqlToCount(select, name); String result = select.toString(); return result; }

调试结果:

大致流程如下(举例说明):

原始sql: Select id, name FROM student WHERE sex=?分解sql存入SelectBody的实现类PlainSelect中,主要的部分是selectItems,fromItem,where然后就是将selectItems替换成count(0)最后在组装成sql返回,组装后的sql是Select count(0) FROM student WHERE sex=? countsql的生成逻辑说完之后,接下来我们看看分页过程。 2. 对sql进行分页

对sql 进行分页的入口逻辑还是在PageInterceptor类的intercept方法中。话不多说,上代码。

//生成分页的缓存 key CacheKey pageKey = cacheKey; //处理参数对象 parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey); //调用方言获取分页 sql String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey); BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter); //设置动态参数 for (String key : additionalParameters.keySet()) { pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } //执行分页查询 resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);

如上,主要四步:

处理参数对象获取待分页的sql,设置动态参数,执行分页查询。 部分问题处理(踩坑) 坑一、在查出数据集合list之后对list做了处理,例如: List taxNoList = juhePayClearingRecordMapper.pageClearingTaxNo(tradeTime); if (taxNoList == null) { return null; } taxNoList = taxNoList.stream().filter(b -> StringUtils.isNotBlank(b)).collect(Collectors.toList()); PageInfo pageInfo = new PageInfo(taxNoList); PagePOJO taxNoInfo = new PagePOJO(); taxNoInfo.setACount((int) pageInfo.getTotal());

如上,先通过SQL语句插入集合taxNoList,然后对taxNoList做了一个去除空字符串的处理,再获取总条数时,数据不对 这是因为查询出来的taxNoList,实际上是一个Page对象,所以获取总条数是调用的((Page)list).getTotal()来获取的。而如果对taxNoList进行处理之后,他就变成了一个普通的ArrayList对象了。所以,获取的总条数total不对。 在这里插入图片描述 2. 坑二、在PageHelper.startPage 方法之后添加了代码,同样的会导致不能分页 在这里插入图片描述

总结

首先感谢liuzh同志开发出了这款好用的插件,代码很规范,插件很好用。本文首先介绍了Mybatis-PageHelper插件的整合与使用,接着介绍了相关原理,主要是统计总条数的实现原理。希望对读者朋友们有所帮助。

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有