系统应用mybatis-plus
版本
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plusartifactId>
<version>2.1.9version>
dependency>
在引入pagehelper-spring-boot-starter
后this.crmDicGroupService.selectPage(page, wrapper);
分页查询失效
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.2.5version>
dependency>
PageInterceptor
拦截的是Executor#query
,而PaginationInterceptor
拦截的是StatementHandler#prepare
,PageInterceptor
优先执行。PageInterceptor
获取RowBounds
是根据参数获取的,在运行环境中,rowBounds
不为空且不为默认数据,!this.dialect.beforePage(ms, parameter, rowBounds)
判断为true,会直接生成对应的boundSql语句,执行executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, pageBoundSql);
。当PaginationInterceptor
拦截到数据的时候,发现RowBounds
数据是RowBounds.DEFAULT
,不会执行分页方法。
PageInterceptor#intercept
,pagehelper-spring-boot-starter
中的拦截器。
@Intercepts({@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class PageInterceptor implements Interceptor {
protected Cache<String, MappedStatement> msCountMap = null;
private Dialect dialect;
private String default_dialect_class = "com.github.pagehelper.PageHelper";
private Field additionalParametersField;
private String countSuffix = "_COUNT";
public PageInterceptor() {
}
public Object intercept(Invocation invocation) throws Throwable {
try {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement)args[0];
Object parameter = args[1];
RowBounds rowBounds = (RowBounds)args[2];
ResultHandler resultHandler = (ResultHandler)args[3];
Executor executor = (Executor)invocation.getTarget();
CacheKey cacheKey;
BoundSql boundSql;
if (args.length == 4) {
boundSql = ms.getBoundSql(parameter);
cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
} else {
cacheKey = (CacheKey)args[4];
boundSql = (BoundSql)args[5];
}
List resultList;
if (this.dialect.skip(ms, parameter, rowBounds)) {
resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
} else {
String msId = ms.getId();
Configuration configuration = ms.getConfiguration();
Map<String, Object> additionalParameters = (Map)this.additionalParametersField.get(boundSql);
if (this.dialect.beforeCount(ms, parameter, rowBounds)) {
String countMsId = msId + this.countSuffix;
MappedStatement countMs = this.getExistedMappedStatement(configuration, countMsId);
Long count;
if (countMs != null) {
count = this.executeManualCount(executor, countMs, parameter, boundSql, resultHandler);
} else {
countMs = (MappedStatement)this.msCountMap.get(countMsId);
if (countMs == null) {
countMs = MSUtils.newCountMappedStatement(ms, countMsId);
this.msCountMap.put(countMsId, countMs);
}
count = this.executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);
}
if (!this.dialect.afterCount(count, parameter, rowBounds)) {
Object var24 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds);
return var24;
}
}
if (!this.dialect.beforePage(ms, parameter, rowBounds)) {
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
} else {
parameter = this.dialect.processParameterObject(ms, parameter, boundSql, cacheKey);
String pageSql = this.dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);
BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);
Iterator var17 = additionalParameters.keySet().iterator();
while(true) {
if (!var17.hasNext()) {
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, pageBoundSql);
break;
}
String key = (String)var17.next();
pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
}
}
Object var22 = this.dialect.afterPage(resultList, parameter, rowBounds);
return var22;
} finally {
this.dialect.afterAll();
}
}
}
PaginationInterceptor#intercept
,MybatisPlus
低版本拦截器
@Intercepts({@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)})
public class PaginationInterceptor extends SqlParserHandler implements Interceptor {
private static final Log logger = LogFactory.getLog(PaginationInterceptor.class);
private ISqlParser sqlParser;
private boolean overflowCurrent = false;
private String dialectType;
private String dialectClazz;
private boolean localPage = false;
public PaginationInterceptor() {
}
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
} else {
RowBounds rowBounds = (RowBounds)metaObject.getValue("delegate.rowBounds");
if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
if (!this.localPage) {
return invocation.proceed();
}
rowBounds = PageHelper.getPagination();
if (rowBounds == null) {
return invocation.proceed();
}
}
BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
String originalSql = boundSql.getSql();
Connection connection = (Connection)invocation.getArgs()[0];
DBType dbType = StringUtils.isNotEmpty(this.dialectType) ? DBType.getDBType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
if (rowBounds instanceof Pagination) {
Pagination page = (Pagination)rowBounds;
boolean orderBy = true;
if (page.isSearchCount()) {
SqlInfo sqlInfo = SqlUtils.getOptimizeCountSql(page.isOptimizeCountSql(), this.sqlParser, originalSql);
orderBy = sqlInfo.isOrderBy();
this.queryTotal(this.overflowCurrent, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
if (page.getTotal() <= 0) {
return invocation.proceed();
}
}
String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy);
originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
} else {
originalSql = DialectFactory.buildPaginationSql((RowBounds)rowBounds, originalSql, dbType, this.dialectClazz);
}
metaObject.setValue("delegate.boundSql.sql", originalSql);
metaObject.setValue("delegate.rowBounds.offset", 0);
metaObject.setValue("delegate.rowBounds.limit", 2147483647);
return invocation.proceed();
}
}
}
MybatisPlus
升级版本,可以解决该问题。引入MybatisPlus
版本。
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.2version>
dependency>
低版本获取的代理对象是MapperProxy
,高版本获取的代理对象是MybatisMapperProxy
。
低版本会调用MapperMethod#executeForMany
,判断参数中带有rowBounds
,执行带有rowBounds
的sqlSession#selectList
方法。
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
result = sqlSession.selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
带有rowBounds
的sqlSession#selectList
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}
高版本会调用MybatisMapperMethod#executeForIPage
,会执行sqlSession#selectList
private <E> Object executeForIPage(SqlSession sqlSession, Object[] args) {
IPage<E> result = null;
Object[] var4 = args;
int var5 = args.length;
for(int var6 = 0; var6 < var5; ++var6) {
Object arg = var4[var6];
if (arg instanceof IPage) {
result = (IPage)arg;
break;
}
}
Assert.notNull(result, "can't found IPage for args!", new Object[0]);
Object param = this.method.convertArgsToSqlCommandParam(args);
List<E> list = sqlSession.selectList(this.command.getName(), param);
result.setRecords(list);
return result;
}
不带rowBounds
的sqlSession#selectList
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
高版本的分页拦截器,PaginationInnerInterceptor#willDoQuery
。
@Override
public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
if (page == null || page.getSize() < 0 || !page.searchCount()) {
return true;
}
BoundSql countSql;
MappedStatement countMs = buildCountMappedStatement(ms, page.countId());
if (countMs != null) {
countSql = countMs.getBoundSql(parameter);
} else {
countMs = buildAutoCountMappedStatement(ms);
String countSqlStr = autoCountSql(page, boundSql.getSql());
PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
countSql = new BoundSql(countMs.getConfiguration(), countSqlStr, mpBoundSql.parameterMappings(), parameter);
PluginUtils.setAdditionalParameter(countSql, mpBoundSql.additionalParameters());
}
CacheKey cacheKey = executor.createCacheKey(countMs, parameter, rowBounds, countSql);
List<Object> result = executor.query(countMs, parameter, rowBounds, resultHandler, cacheKey, countSql);
long total = 0;
if (CollectionUtils.isNotEmpty(result)) {
// 个别数据库 count 没数据不会返回 0
Object o = result.get(0);
if (o != null) {
total = Long.parseLong(o.toString());
}
}
page.setTotal(total);
return continuePage(page);
}