Spring Boot + Mybatis-Plus 集成与使用(六)
前言:
上章节中我们讲解了MyBatis-Plus如何强化XML映射文件与注解SQL,以及使用分页插件做分页查询。今天给各位同伴们分析下分页插件的分页原理,以及安利一款基于INTELLIJ IDEA的快速开发插件-MybatisX。
一、分页原理
上章节我们使用了分页插件类PaginationInterceptor类进行分页查询操作。本章节我们来分析PaginationInterceptor是如何处理分页查询的sql语句。
我们来看下PaginationInterceptor的源码
[code]@Intercepts({@Signature( type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class} )}) public class PaginationInterceptor extends AbstractSqlParserHandler implements Interceptor
在该类上定义了@Intercepts注解,实现Interceptor接口的intercept方法,该类定义为Mybatis容器里的一个拦截器。拦截StatementHandler接口的子类的prepare方法。StatementHandler主要负责处理Mybatis与JDBC之间Statement的交互,而Statement是负责与数据库进行交互的对象。
我们再来分析下intercept方法的实现
[code]public Object intercept(Invocation invocation) throws Throwable { //拿到拦截的目标类,StatementHandler的子类 StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget()); MetaObject metaObject = SystemMetaObject.forObject(statementHandler); //解析预处理Mapper接口方法的最初sql this.sqlParser(metaObject); MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement"); //判断是否为查询方法操作 if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) { //获取BoundSql对象,BoundSql对象是用于存储sql语句及对应的参数相关的对象 BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql"); //获取参数对象 Object paramObj = boundSql.getParameterObject(); IPage<?> page = null; //判断参数对象是否为IPage实现类,将对象引用给page对象 if (paramObj instanceof IPage) { page = (IPage)paramObj; } else if (paramObj instanceof Map) { Iterator var8 = ((Map)paramObj).values().iterator(); while(var8.hasNext()) { Object arg = var8.next(); if (arg instanceof IPage) { page = (IPage)arg; break; } } } //判断page是否为空并且每页条数大于等于0 if (null != page && page.getSize() >= 0L) { //每页条数大于默认条数,则每页条数默认条数,默认条数为500 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 = StringUtils.isNotEmpty(this.dialectType) ? DbType.getDbType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL()); //判断是否查询数据总条数 if (page.isSearchCount()) { SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql); this.queryTotal(this.overflow, sqlInfo.getSql(), mappedStatement, boundSql, page, connection); if (page.getTotal() <= 0L) { return null; } } //用于拼接sql的排序字段 String buildSql = concatOrderBy(originalSql, page); //分页查询重点在这里,用于拼接分页的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); return invocation.proceed(); } else { return invocation.proceed(); } } else { return invocation.proceed(); } }
代码中MetaObject是用于包装Object对象,将Object对象包装成ObjectWrapper,MapWrapper,CollectionWrapper,BeanWrapper等,ObjectWrapper是对应属性及方法的一个包装类,MetaObject获取obejct的属性值,以及给属性设值。
我们将拼接分页限定语句拿来再分析下
[code] DialectModel model = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
可以看到这里通过 DialectFactory.buildPaginationSql()方法分别传入page对象、拼接排序后的buildSql的sql字符串,数据库类型对象dbType,还有方言类对象dialectClazz。进入该方法
[code]public static DialectModel buildPaginationSql(IPage<?> page, String buildSql, DbType dbType, String dialectClazz) { return getDialect(dbType, dialectClazz).buildPaginationSql(buildSql, page.offset(), page.getSize()); }
可以看getDialect方法通过数据库类型对象dbType,方言类对象dialectClazz来选择实例化当前的方言实现类对象,调用其buildPaginationSql方法。我们当前是Mysql数据库。我们来看MySqlDialect类的buildPaginationSql()。
[code]public DialectModel buildPaginationSql(String originalSql, long offset, long limit) { String sql = originalSql + " LIMIT " + "?" + "," + "?"; return (new DialectModel(sql, offset, limit)).setConsumerChain(); }
我们可以看到,在该方法里最终完成的分页限定语句的拼接。
到这里,我们对分页插件的分析就到此。对分页的原理分析的还比较浅显。有兴趣的同伴们可以留言与我们一起探讨。
二、MybatisX快速开发插件
这里给各位同伴们安利一个开发插件MybatisX,是一款基于INTELLIJ IDEA的快速开发插件。
安装方法用两种:
- 打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入
mybatisx
搜索并安装。
- 打开idea官网 https://plugins.jetbrains.com,搜索MybatisX
下载后,打开 IDEA,进入 File -> Settings -> Plugins -> install plugin from disk,选择刚下载的MybatisX-idea.0.1.0.jar文件。
注意重启Idea。
功能
- Java 与 XML 调回跳转
安装MyBatisX插件后,我们可以在Mapper接口类中看,在类和方法前多了Mybatis的标志图标。同时,在方法映射的XML文件里的sql标签前也多了图标,点击图标,可以实现Java 与 XML 来回跳转,方便我们手动找对应文件。
- Mapper 方法自动生成 XML
我们在Mapper接口定义一个方法,再使用Idea 快捷键Alt + Enter,弹出智能提示,在提示中我们看有两个Mybatis的选项:
- Generate @Param
- Generate new statement
我们选择Generate new statement后,自动跳转到XML映射文件,并生成一个待编写sql语句的以方法为id的查询标签。
- Mapper 方法自动生成@Param注解
我们再来试下Generate @Param,选择后,自动在参数前添加 @Param,默认值为参数名
MyBatis还是一款不错的开发插件,目前已停更,有点可惜。希望能再维护开发更多的功能支持。
三、小结
本章节浅显的分析了MyBatis-Plus的分页插件的原理,以及介绍了开发插件MyBatisX的安装与功能使用。下章节我们将给各位同伴讲解MyBatis-Plus的代码生成功能。
扫描下方二维码,关注微信公众号,掌握最新动态。与关注的同伴们一起学习,一起编程!
- 点赞
- 收藏
- 分享
- 文章举报
- Spring Boot + Mybatis-Plus 集成与使用(七)
- 使用SpringBoot搭建小型项目,集成mybatis,redis,swagger2,并部署在外部容器中。
- 架构实战项目心得(七):使用SpringBoot+Dubbo+Mybatisplus+Oracle搭建后台项目框架(一)
- 在springboot项目中使用mybatis 集成 Sharding-JDBC
- SpringBoot之集成mybatis:使用mybatis xml
- springboot+mybatisplus(使用总结,配置总结!!!干货...)
- spring boot 集成 mybatis 使用redis做二级缓存
- spring-boot-mybatis-plus使用心得
- spring-boot集成mybatis使用Druid监控
- (二十一)SpringBoot之集成mybatis:使用mybatis xml
- Spring Boot 使用Oracle集成Mybatis,驼峰映射(下划线)问题
- SpringBoot实践:集成Mybatis-Plus
- Mybatis-plus集成springboot
- Springboot-2.0.6.RELEASE版本集成Mybatis-plus及Mysql
- springboot2.0.5集成mybatis(PageHelper分页插件、generator插件使用)
- SpringBoot和mybatisplus的入门使用
- (二十)SpringBoot之集成mybatis:使用mybatis注解
- springboot 零xml集成mybatis-plus
- 从零学spring boot--集成mybatis--项目--使用注解方式
- springboot+mybatis-plus集成