您的位置:首页 > 编程语言 > Java开发

Spring Boot + Mybatis-Plus 集成与使用(六)

2020-01-14 13:27 826 查看

前言:

上章节中我们讲解了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,进入 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的选项:

  1. Generate @Param
  2. Generate new statement

我们选择Generate new statement后,自动跳转到XML映射文件,并生成一个待编写sql语句的以方法为id的查询标签。

  • Mapper 方法自动生成@Param注解

我们再来试下Generate @Param,选择后,自动在参数前添加 @Param,默认值为参数名

MyBatis还是一款不错的开发插件,目前已停更,有点可惜。希望能再维护开发更多的功能支持。

三、小结

本章节浅显的分析了MyBatis-Plus的分页插件的原理,以及介绍了开发插件MyBatisX的安装与功能使用。下章节我们将给各位同伴讲解MyBatis-Plus的代码生成功能。

扫描下方二维码,关注微信公众号,掌握最新动态。与关注的同伴们一起学习,一起编程!

 

  • 点赞
  • 收藏
  • 分享
  • 文章举报
伴学编程 发布了9 篇原创文章 · 获赞 3 · 访问量 1255 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: