分页插件的部分源码(浅)
本文章根据*乎博主“京思祺”博主的文章引领理解的
配置bean:
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
下面是PaginationInterceptor中**intercept()**部分的源码
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);//解析sql
//sql拦截器,可以设置id属性拦截具体sql
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
//判断是否sql语句
if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) {
//获取sql语句中保存的参数信息
BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
Object paramObj = boundSql.getParameterObject();
IPage<?> page = null;
//判断保存的对象是否是ipage对象
if (paramObj instanceof IPage) {
page = (IPage)paramObj;
} else if (paramObj instanceof Map) {
//判断是否为map对象,是的话获取map迭代器,判断map中是否有ipage对象
Iterator var8 = ((Map)paramObj).values().iterator();
while(var8.hasNext()) {
Object arg = var8.next();
if (arg instanceof IPage) {
page = (IPage)arg;
break;
}
}
}
//如果对象不为空
if (null != page && page.getSize() >= 0L) {
//处理单条页数限制
if (this.limit > 0L && this.limit <= page.getSize()) {
page.setSize(this.limit);
}
//取出sql建立数据库连接
String originalSql = boundSql.getSql();
Connection connection = (Connection)invocation.getArgs()[0];
//获取数据库类型 DBType是一个枚举类,里面标识了各大数据库系统
DbType dbType = StringUtils.isNotEmpty(this.dialectType) ? DbType.getDbType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
if (page.isSearchCount()) {
//优化count
SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql);
//查询count
this.queryTotal(this.overflow, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
if (page.getTotal() <= 0L) {
return null;
}
}
//连接orderby 自定义排序
String buildSql = concatOrderBy(originalSql, page);
//重构sql,加了个limit()达到分页效果
DialectModel model = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
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);
//执行sql
return invocation.proceed();
} else {
return invocation.proceed();
}
} else {
return invocation.proceed();
}
}
大概的流程就是:通过invocation来获取statementHandler再获取原生的sql语句,利用BoundSql 中保存的用户传入的数据来判断是否是ipage的实例,是的话执行接下来的sql解析缓解,不是的话直接跳过进行sql查询返回。在sql解析这个分支中先是判断处理了单条sql执行返回的条数SetSize(),然后建立数据库连接获取当前数据库系统的类型,接下来就是优化count和加入limit执行条件来填充ipage对象中的属性执行sql。
本文章内容仅供参考,所写内容为本人自己理解,只是稍微了解了一下大概流程,内部细节没有多看,如果错误之处欢迎大佬指正,谢谢