MyBatis 源码分析 之SqlSession接口和Executor类

 更新时间:2017年02月04日 11:35:27   作者:Aomi  
mybatis框架在操作数据的时候,离不开SqlSession接口实例类的作用,下面通过本文给大家实例剖析MyBatis 源码分析之SqlSession接口和Executor类,需要的朋友参考下吧

mybatis框架在操作数据的时候,离不开SqlSession接口实例类的作用。可以说SqlSession接口实例是开发过程中打交道最多的一个类。即是DefaultSqlSession类。如果笔者记得没有错的话,早期是没有什么getMapper方法的。增删改查各志有对应的方法进行操作。虽然现在改进了很多,但是也保留了很多。我们依旧可以看到类似于selectList这样子的方法。源码的例子里面就可以找到。如下

SqlSession session = sqlMapper.openSession(TransactionIsolationLevel.SERIALIZABLE);
  try {
   List<Author> authors = session.selectList("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors");
   assertEquals(2, authors.size());
  } finally {
   session.close();

当然从某种意义上来讲,写起有一点烦。但是不可否认他的功能的确存在。这也是笔者为什么比较喜欢用动态代理来进行数据上的操作。至少可观性上笔者认为比较好吧。

不管是哪一种数据上的操作都离不开SqlSession接口实例。所以深入查看qlSession接口实例就显得相当的重要。笔者选择了DefaultSqlSession类的selectList方法作为入口点进行切入。代码如下。

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
   MappedStatement ms = configuration.getMappedStatement(statement);
   return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  } catch (Exception e) {
   throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  } finally {
   ErrorContext.instance().reset();
  }
 }

源码的意思是从configuration变理里面获得,在通过Executor类的query方法获得相应的结果。让我们想想上一章中讲过MappedStatement类是用于存放select节点或是update节点的信息。也就是说这里传入statement参数表示将要去执行哪一个select节点。传入的参数自然就是select节点id对应的值。那么Executor类又是什么。如果比较认真的人来查看源码的话,你会发现基本上都会用到Executor类实例。在一次叹气——架构之美。

DefaultSqlSession类的成员executor是在构造函数里面给他赋值的。所以我们又要回头去查看一下是在什么时候实例化了DefaultSqlSession类。笔者在第一章结尾的时候也讲到过关于Executor类。从源码中我们可以看到他是通过Configuration类的newExecutor方法来得到的。代码如下

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  executorType = executorType == null ? defaultExecutorType : executorType;
  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  Executor executor;
  if (ExecutorType.BATCH == executorType) {
   executor = new BatchExecutor(this, transaction);
  } else if (ExecutorType.REUSE == executorType) {
   executor = new ReuseExecutor(this, transaction);
  } else {
   executor = new SimpleExecutor(this, transaction);
  }
  if (cacheEnabled) {
   executor = new CachingExecutor(executor);
  }
  executor = (Executor) interceptorChain.pluginAll(executor);
  return executor;
 }

 完了。没有想到Executor类还有分种类的。说实话笔者若是没有去查看源码真不会知道原来Executor类还有分种类的。看上面的源码笔者刚开始认为有四种。但是发现最后一个跟上面的三个实例上有一点不同。为了更进一步确认笔者不得不去查看一下官网上面的API。笔者把内容复制过来。如下。

ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。

ExecutorType.REUSE: 这个执行器类型会复用预处理语句。

ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。

看样子官网解释的很清楚了。笔者就不在这里多言了。那么默认情况下mybatis框架又是调用哪一个Executor子类呢?其实这一点是可以在源码上找到的。如下

Configuration类:

protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

相信大家都明白了如果都没有指定相应的Executor类的类型的话,mybatis框架会去调用SimpleExecutor类。

对于Executor类我先了解到这里。因为后面大量要用到他,同时也只有结合后面的功能才明白Executor类的作用。从上面DefaultSqlSession类的selectList方法中我们可以发现最后会去调用Executor类的query方法。

return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

对于变量ms笔者就不多说了。wrapCollection方法却是值得注意的。他意思是先判断变理parameter是否是Collection类型,如果是,就是新建一个StrictMap类型并以“collection”为key进行存放。又查一下是不是List类型。如果是,就以“list”为key进行存放。接下就是判断是不是数组类型,如果是,就是新建一个StrictMap类型并以“array”为key进行存放。最后返回回StrictMap类实例。当然如果上面都不是的话,就直接返回parameter了。如果不清楚为什么设计者要这样子做不要紧,笔者这个时候也不知道为什么。所以笔者只要记得他做了什么。RowBounds类型变理rowBounds一般用于分页。默认是0到2147483647值,相信这个够你用了吧。ResultHandler是用于处理返回的结果,这里直接就不要处理返回的结果了。所以笔者就不用讲了。

BaseExecutor类:

 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  BoundSql boundSql = ms.getBoundSql(parameter);
  CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
  return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
 }

类似于SimpleExecutor这样子类并不是直接的继承了Executor类。而是通过BaseExecutor类这一层之后到继承Executor类。所以query方法调用的时候并不是调用SimpleExecutor类的。而是调用BaseExecutor类的。当然你从SimpleExecutor类也找不到query方法。显然是经过BaseExecutor类进行处理相关的信息之后,在去调用Executor子类的doQuery方法。所以我们可以找到SimpleExecutor类的doQuery方法。这个过程笔者就不想细说。笔者主要目地还是引导大家去看的。

SimpleExecutor类:

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  try {
   Configuration configuration = ms.getConfiguration();
   StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
   stmt = prepareStatement(handler, ms.getStatementLog());
   return handler.<E>query(stmt, resultHandler) ; 
  } finally {
   closeStatement(stmt);
  }
 }

  从源码上来看笔者只认识俩个类一个是Configuration类和Statement类。Statement类是属于JDBC的知识点。Configuration类是属于mybatis框架的配置信息部分。意思就是通过MappedStatement获得Configuration类的信息。在通过Configuration类新建StatementHandler接口实例。而StatementHandler接口实例就是用来处理生成Statement类的。很明显就是执行SQL语句就是在StatementHandler接口实例里面。

笔者来一个小结:动态代理的方式事实上最后还是动用SqlSession接口实例的方法。所以只有了解了SqlSession接口实例的方法就是可以进一步深入。而SqlSession接口实例执行方法的过程中又会去执行Executor类的方法。而关于Configuration类的作用可以说是任务时候都有可以初动用。当前最后的任务暂时是交给了Executor类的子类。

好了。到了这里面,关于SqlSession接口和Executor类的作用就有一个大概的像想空间。当然只望一下就明白SqlSession接口和Executor类的话,笔者觉得有一点难。至少笔者没有这样子的能力。在笔者看来SqlSession接口和Executor类的工作在doQuery方法的时候,就已经圆完的结束了。虽然笔者并没有说出SqlSession接口和Executor类的作用。主要还是靠你们自己去理解了。接下就来就是了解一下StatementHandler接口的作用。

以上所述是小编给大家介绍的MyBatis 源码分析 之SqlSession接口和Executor类,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • Java程序图形用户界面设计之标签组件

    Java程序图形用户界面设计之标签组件

    图形界面(简称GUI)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受,本篇精讲Java语言中关于图形用户界面的标签组件部分
    2022-02-02
  • Java停止线程的3种方法

    Java停止线程的3种方法

    这篇文章主要分享Java停止线程的3种方法,分别是自定义中断标识符,停止线程、使用线程中断方法interrupt停止线程、使用stop停止线程。下文详细介绍需要的小伙伴可以参考一下
    2022-05-05
  • Java递归造成的堆栈溢出问题及解决方案

    Java递归造成的堆栈溢出问题及解决方案

    在Java中,递归造成的堆栈溢出问题通常是因为递归调用的深度过大,导致调用栈空间不足,解决这类问题的一种常见方法是使用非递归的方式重写算法,即使用迭代替代递归,需要的朋友可以参考下
    2024-08-08
  • java实现学生成绩档案管理系统

    java实现学生成绩档案管理系统

    这篇文章主要为大家详细介绍了java实现学生成绩档案管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 解决使用IDEA时跳转到.class的问题

    解决使用IDEA时跳转到.class的问题

    这篇文章主要介绍了解决使用IDEA时跳转到.class的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • SpringMVC中Controller层获取前端请求参数的方式汇总

    SpringMVC中Controller层获取前端请求参数的方式汇总

    这篇文章主要介绍了SpringMVC中Controller层获取前端请求参数的几种方式,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Java 单链表数据结构的增删改查教程

    Java 单链表数据结构的增删改查教程

    这篇文章主要介绍了Java 单链表数据结构的增删改查教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 浅谈Spring事务传播行为实战

    浅谈Spring事务传播行为实战

    这篇文章主要介绍了浅谈Spring事务传播行为实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • SpringBoot中动态数据源配置与使用详解

    SpringBoot中动态数据源配置与使用详解

    在现代应用中,处理多数据源是常见的需求,在 Spring Boot 中,这样的需求可以通过动态数据源来轻松实现,本篇博客将详细介绍如何在 Spring Boot 中配置和使用动态数据源,并演示如何切换到指定的数据源,需要的朋友可以参考下
    2024-10-10
  • SpringBoot模拟实现流式输出效果

    SpringBoot模拟实现流式输出效果

    这篇文章主要为大家详细介绍了如何使用SpringBoot模拟实现流式输出效果,并在前端使用流式接收数据并打印,感兴趣的小伙伴可以参考一下
    2025-03-03

最新评论