MyBatis-Plus分页插件Page原理分析

随着框架的升级,很多功能都帮我们封装好了,可以直接拿来用,方便我们开发

今天我要说的是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的处理完成分页操作。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值