博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis源码分析-BaseExecutor
阅读量:4699 次
发布时间:2019-06-09

本文共 5234 字,大约阅读时间需要 17 分钟。

根据前文的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下BaseExecutor如何解析执行sql语句

BaseExecutor-抽象类

其是Executor接口的实现类但为抽象类,另外一个则为具体实现类为CachingExecutor,主要是通过对象适配的设计模式在原来的executor上再附上缓存的属性,有兴趣的可自行查阅。先从构造函数看一发

protected BaseExecutor(Configuration configuration, Transaction transaction) {    //事务对象    this.transaction = transaction;    this.deferredLoads = new ConcurrentLinkedQueue
(); this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); //表明exector的状态 this.closed = false; //主文件属性,主要获取MappedStatement对象 this.configuration = configuration; this.wrapper = this; }

BaseExecutor#update()-SqlSession之insert/update/delete入口

具体源码如下

@Override  public int update(MappedStatement ms, Object parameter) throws SQLException {    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());    if (closed) {      throw new ExecutorException("Executor was closed.");    }    clearLocalCache();    //供子类复写执行CUD操作    return doUpdate(ms, parameter);  }

BaseExecutor#query()-SqlSession之select入口

具体源码如下

@Override  public 
List
query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //获取绑定的sql,并将参数对象与sql语句的#{}一一对应 BoundSql boundSql = ms.getBoundSql(parameter); //获取cacheKey供缓存,包含完整的语句、参数等 CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); //比原先多传入CacheKey和BoundSql参数 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }

具体的查询处理逻辑如下

@Override  public 
List
query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } //是否清除本地缓存 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List
list; try { queryStack++; //如果查询的语句已存在本地缓存中,则直接从本地获取,反之从数据库中读取内容 list = resultHandler == null ? (List
) localCache.getObject(key) : null; if (list != null) { //此处尝试对Callable类型的表达式进行处理,主要是针对mode=out类型的参数 //此参数主要是通过map来定义,直接从map中获取 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //从数据库中获取并进行缓存处理,其也会调用子类需复写的doQuery()方法 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }

由上可知,BaseExecutor对CRUD操作均转化为对子类的doUpdate()/doQuery()方法的调用,并一般都会相应的结果进行缓存以免频繁请求数据库导致性能下降。本文则从SimpleExecutor子类来进行分析

SimpleExecutor

分别看下SimpleExecutor复写的doUpdate()和doQuery()方法,具体源码如下

doUpdate()

@Override  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {    Configuration configuration = ms.getConfiguration();    //创建StatementHandler来处理update()    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);    //创建表达式对象Statement    Statement stmt = prepareStatement(handler, ms.getStatementLog());    return handler.update(stmt);  }

doQuery()

@Override  public 
List
doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Configuration configuration = ms.getConfiguration(); //创建StatementHandler来处理query() StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); //创建表达式对象Statement Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.
query(stmt, resultHandler); }

doUpdate()/doQuery()代码的执行逻辑一致,均是先创建StatementHandler对象,然后通过prepareStatement()方法创建表达式对象,供前者调用处理update/query方法

SimpleExecutor#prepareStatement()-创建预表达式对象

逻辑如下

//handler对象对应的为RoutingStatementHandler对象,其实也是个适配管理类  //可根据MappedStatement的statementType来确定表达式处理handler类,后续讲解  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {    Statement stmt;    //获取连接对象,如果该日志等级为debug,则会打印相应的处理日志,采用代理实现    Connection connection = getConnection(statementLog);    //创建真实的Statement对象,比如SimpleStatement/PreparedStatement/CallableStatement    stmt = handler.prepare(connection, transaction.getTimeout());    //请求参数,常用在preparedStatement用来设置相应的请求参数    handler.parameterize(stmt);    return stmt;  }

小结

  1. BaseExecutor抽象类提供了对CRUD操作的入口,并带有缓存效应,子类只需要复写doUpdate()和doQuery()抽象方法即可

  2. SimpleExecutor-简单的处理实现类,即基本每次对相同的sql语句都会创建新的Statement对象;ReuseExecutor-复用处理实现类,即对相同的sql语句会缓存Statement对象;BatchExecutor-批处理实现类

  3. 最终获取Statement对象以及执行sql语句的解释权在于StatementHandler接口,详情看下节内容

转载于:https://www.cnblogs.com/question-sky/p/7353418.html

你可能感兴趣的文章
Summary of CRM 2011 plug-in
查看>>
Eclipse+Maven环境下java.lang.OutOfMemoryError: PermGen space及其解决方法
查看>>
安全漏洞之Java
查看>>
Oracle 组函数count()
查看>>
Session的使用过程中应注意的一个小问题
查看>>
SDK,API,DLL名词解释
查看>>
试探算法
查看>>
jquery.validation.js 使用
查看>>
数据库高级查询
查看>>
C语言实现封装、继承和多态
查看>>
创建文件
查看>>
Nginx 相关介绍
查看>>
leetcode[33]Search in Rotated Sorted Array
查看>>
安卓上按钮绑定监听事件的两种写法
查看>>
OpenCV Shi-Tomasi角点检测子
查看>>
eval(PHP 4, PHP 5)
查看>>
readelf用法小记
查看>>
结对编程进展总结
查看>>
Java中JavaScript unescape与escape函数算法
查看>>
js的基础要点
查看>>