欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-08 10:11:22
mybatis框架在操作数据的时候,离不开sqlsession接口实例类的作用。可以说sqlsession接口实例是开发过程中打交道最多的一个类。即是defaultsqls...

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类,希望对大家有所帮助