通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)),

今天我们分析下Mybatis如何创建SqlSession( sessionFactory.openSession())和Excutor到底做了什么事情

还是上篇的代码demo

  public static void main(String[] args) throws Exception {
        SqlSessionFactory sessionFactory = null;
        String resource = "configuration.xml";
        sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
        SqlSession sqlSession = sessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(userMapper.findUserById(1));
  }

1:openSessionFromDataSource

通过openSession()最终调用的是 openSessionFromDataSource,源码如下:

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

说明:ExecutorType(执行器类型)类型有 SIMPLE(默认),REUSE,BATCH,

TransactionIsolationLevel  隔离级别5种

NONE(Connection.TRANSACTION_NONE),

READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),

READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),

REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),

SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);

通过源码看出首先是从configuration获取environment,接着创建Transaction,

最后通过 configuration.newExecutor创建Executor。

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    //根据executorType创建不同的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;
  }

根据executorType创建对应的Executor,从源码可以看出他有BatchExecutor、ReuseExecutor、CachingExecutor、SimpleExecutor

那么Executor是做什么的呢?

2:Executor

Executor是接口,是对于Statement的封装,我们看下Executor,他是真正执行sql的地方。

public interface Executor {
  ResultHandler NO_RESULT_HANDLER = null;
  int update(MappedStatement ms, Object parameter) throws SQLException;
   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
   Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
  List flushStatements() throws SQLException;
  void commit(boolean required) throws SQLException;
  void rollback(boolean required) throws SQLException;
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
  boolean isCached(MappedStatement ms, CacheKey key);
  void clearLocalCache();
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType);
  Transaction getTransaction();
  void close(boolean forceRollback);
  boolean isClosed();
  void setExecutorWrapper(Executor executor);
}

上面源码我可以看到Executor接口定义了update 、query、commit、rollback等方法,他的实现类如下图

我们拿其中的SimpleExecutor类里面的doQuery方法看下源码

  @Override
  public  List 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);
//StatementHandler封装了Statement, 让 StatementHandler 去处理
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

我们看看StatementHandler 的一个实现类 PreparedStatementHandler(这也是我们最常用的,封装的是PreparedStatement), 看看它使怎么去处理的:

  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    //这个和jdbc一样执行sql
    statement.execute(sql);
    //结果交给了ResultSetHandler 去处理
    return resultSetHandler.handleResultSets(statement);
  }

以上是sql底层执行的基本流程,说的直白一点就是所以sql底层都交给了Excutor,我们将在下一讲中分析上一层的调用,也就是Excutor的上层。

我们继续回到openSessionFromDataSource上面来,通过上面的executor的创建最终是创建

new DefaultSqlSession(configuration, executor, autoCommit);到此我们已经完成了SqlSession的创建,后面我们将分析sqlSession.getMapper 也就是Excutor的上层调用。

Mybatis源码分析之SqlSession和Excutor(二)的更多相关文章

  1. 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  2. 精尽 MyBatis 源码分析 - SqlSession 会话与 SQL 执行入口

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  3. MyBatis 源码分析

    MyBatis 运行过程 传统的 JDBC 编程查询数据库的代码和过程总结. 加载驱动. 创建连接,Connection 对象. 根据 Connection 创建 Statement 或者 Prepa ...

  4. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  5. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  6. MyBatis源码分析(4)—— Cache构建以及应用

    @(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...

  7. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  8. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  9. MyBatis源码分析之环境准备篇

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

随机推荐

  1. 智能指针scoped_ptr

    对应C++11中的unique_ptr #include <iostream> #include <memory> class foo { public: foo() { st ...

  2. WCF中修改接口或方法名称而不影响客户端程序

    本篇接着"从Web Service和Remoting Service引出WCF服务"中有关WCF的部分. 运行宿主应用程序. 运行Web客户端中的网页. 输入内容,点击按钮,能获取 ...

  3. iOS objc_msgSend 报错解决方案

    错误代码: objc_msgSend(self.beginRefreshingTaget, self.beginRefreshingAction, self); Too many arguments ...

  4. C#编程(五十一)----------链表

    原文链接: http://blog.csdn.net/shanyongxu/article/details/47024865 链表 LinkedList<T>集合类没有非泛型类的版本,它是 ...

  5. Mysql导入大容量SQL文件数据问题

    mysql在通过导入sql文件可能会出现下面二个问题: 1.如果sql文件过大,会出现"MySQL server has gone away"问题; 2.如果sql文件数据有中文, ...

  6. runOnUiThread更新主线程

    更新UI采用Handle+Thread,需要发送消息,接受处理消息(在回调方法中处理),比较繁琐.除此之外,还可以使用runOnUiThread方法.   利用Activity.runOnUiThre ...

  7. cloudera项目源代码

    以下项目都需要安装git,Linux的git还是比较容易安装的,windows的git安装参考项目区域:软件版本控制-在Windows中使用Git视频介绍 git相关软件安装参考win7安装 git软 ...

  8. Swift - CALayer的contents属性动画

    Swift - CALayer的contents属性动画 效果 源码 https://github.com/YouXianMing/Swift-Animations // // LiveImageVi ...

  9. QML与C++交互:在qml中使用QSqlQueryModel显示数据库数据

    QML与C++交互:在qml中使用QSqlQueryModel显示数据库数据 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 參考链接: http:// ...

  10. bash 设置

    export COLUMNS=500 $* 将所有命令行参数当做单个文本值包含 $@ 将所有命令行参数当做独立的文本值包含 $# 命令行参数数目 $? 最近使用的前端进程的退出状态码 $- 当前命令选 ...