通过上一篇文章的分析我们,我初步了解了它是如何创建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. 我所经历的SAP选型[转]

    这是一个失败的选型项目,而且在可遇见的未来公司也不会再经历SAP选型,甚至不会再启动erp项目,个中原因很难一言道尽,在此简要的说说我们的选型过程以及在选型过程中对各种因素的考虑. 一.重启选型工作七 ...

  2. AngularJS自定义Directive初体验

    通常我们这样定义个module并随之定义一个controller. var app = angular.module('myApp', []); app.controller('CustomersCo ...

  3. C#编程(三十五)----------foreach和yield

    枚举 在foreach语句中使用枚举,可以迭代集合中的元素,且无需知道集合中的元素个数. 数组或集合实现带GetEumerator()方法的IEumerable接口.GetEumerator()方法返 ...

  4. android studio每次启动都要在fetching Android sdk compoment information停好久 怎么解决?

    网上有人给出了方案:1)进入刚安装的Android Studio目录下的bin目录.找到idea.properties文件,用文本编辑器打开.2)在idea.properties文件末尾添加一行: d ...

  5. C/C++中结构体(struct)

    c++ 里面struct可以new,另外: C++中,struct关键字与Class关键字基本是一样的,但是,有两点不同 1 struct定义的数据类型里面所有成员默认级别都是共有的,而class里面 ...

  6. Vmware ESXi添加共享磁盘

        1,ssh登录(两个虚拟机所在的宿主机)物理主机,创建共享磁盘(该步骤也可图形化操作) #cd /vmfs/volumes/4ffd9951-2c12a99a-ff2a-3440b59cd4f ...

  7. 两种方法获取MyBatis刚刚插入的id

    主要就是在xml文件中的写法,其他省略 方法一: <insert id="insert" parameterType="com.xxx.xxxx.pojo.User ...

  8. 护士当家第一至七季/全集Nurse Jackie迅雷下载

    英文译名Nurse Jackie,第1-7季(2009-2015)Showtime. 本季看点:<护士当家>是一部黑色医务剧,该剧特别邀请到荣获艾美奖和金球奖的Edie Falco出演女主 ...

  9. serializeArray()与 serialize()

    serialize()序列表表格内容为字符串,用于 Ajax 请求. serializeArray()序列化表格元素 (类似 '.serialize()' 方法) 返回 JSON 数据结构数据. .s ...

  10. [转]PHP与Shell交互

    From : http://blog.csdn.net/houqd2012/article/details/8219199 最近想使用PHP与Sheel进行交互.PHP控制显示和高层的逻辑结构.She ...