随着框架的升级,很多功能都帮我们封装好了,可以直接拿来用,方便我们开发
今天我要说的是MyBatis-Plus框架中的分页插件
一、引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version><!-- 3.2.0 -->
</dependency>
二、使用IPage需要注入一个bean拦截器交给spring进行管理。如下。否则不会进行拦截。
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
三、源码分析
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
// sql解析
this.sqlParser(metaObject);
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) {
BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
// 获取参数对象
Object paramObj = boundSql.getParameterObject();
IPage<?> page = (IPage)ParameterUtils.findPage(paramObj).orElse((Object)null);
// 如果有page对象,说明要分页
if (null != page && page.getSize() >= 0L) {
// limit默认500条,如果你的pageSize大于等于默认条数,取默认500条
if (this.limit > 0L && this.limit <= page.getSize()) {
this.handlerLimit(page);
}
// 得到sql语句
String originalSql = boundSql.getSql();
Connection connection = (Connection)invocation.getArgs()[0];
if (page.isSearchCount() && !page.isHitCount()) {
SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql, metaObject);
// 查询总记录数
this.queryTotal(sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
// 判断当前页码是否大于数据库实际页码
if (!this.continueLimit(page)) {
return null;
}
}
DbType dbType = this.dbType == null ? JdbcUtils.getDbType(connection.getMetaData().getURL()) : this.dbType;
IDialect dialect = (IDialect)Optional.ofNullable(this.dialect).orElseGet(() -> {
return DialectFactory.getDialect(dbType);
});
String buildSql = this.concatOrderBy(originalSql, page);
// 拼接分页语句(limit ?)
DialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize());
Configuration configuration = mappedStatement.getConfiguration();
List<ParameterMapping> mappings = new ArrayList(boundSql.getParameterMappings());
Map<String, Object> additionalParameters = (Map)metaObject.getValue("delegate.boundSql.additionalParameters");
model.consumers(mappings, configuration, additionalParameters);
metaObject.setValue("delegate.boundSql.sql", model.getDialectSql());
metaObject.setValue("delegate.boundSql.parameterMappings", mappings);
// 执行分页查询
return invocation.proceed();
} else {
return invocation.proceed();
}
} else {
return invocation.proceed();
}
}
总结
IPage内部原理也是基于拦截器,但是这个拦截的是方法以及方法中的参数,这个也会判断是否是查询操作。如果是查询操作,才会进入分页的处理逻辑。 进入分页逻辑处理后,拦截器会通过反射获取该方法的参数进行判断是否存在IPage对象的实现类。如果不存在则不进行分页,存在则将该参数赋值给IPage对象。然后进行拼接sql的处理完成分页操作。