通过上一篇文章的分析我们,我初步了解了它是如何创建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. 百度地图api---实现新建地图

    调用这个函数 function refresh() { history.go(0);   } 实现了地图新建

  2. Android应用开发相关下载资源(2015/08/27更新)

    Android应用开发相关下载资源   官方终于发布了Android Studio正式版,Android Studio将会成为推荐使用的主要Android开发工具.   (1)Android SDK ...

  3. AngularJS使用angular-formly进行表单验证

    当验证表单中有很多字段时,这时候可能希望把html的生成以及验证逻辑放到controller中,在页面,也许是这样的: <some-form fiedls="vm.someFields ...

  4. android studio一直卡在Gradle:Executing tasks

    http://www.eoeandroid.com/forum.php?mod=viewthread&tid=554227 新建了个hello world项目,运行就卡在Gradle:Exec ...

  5. cocos2d-x调用scheduleUpdate()不执行update()方法的解决办法

    前两天使用到每帧都更新动画的scheduleUpdate()方法,但通过cclog,我发现, scheduleUpdate()是执行了.但update()方法并没有被调用. 那是因为在CCLayer中 ...

  6. 实用ExtJS教程100例-001:开天辟地的Hello World

    ExtJS功能繁多,要想彻底的了解确实很困难.作为初学者,如何能找到一条快速的通道呢?我觉得,如果你有Javascript的基础,那就不要惧怕ExtJS的复杂,从动手开始,遇到问题,解决问题,积累经验 ...

  7. Java生成8位随机邀请码,不重复

    public static String[] chars = new String[] { "a", "b", "c", "d&q ...

  8. Java(C#)基础差异-数组

    1.填充数组 Java 数组填充替换方法Arrays.fill() 举例如下: import java.util.Arrays; public class FillDemo { public stat ...

  9. MySQL 查询优化简记

    今天尝试对一张MySQL表做查询优化, 500W数据 但是发现加了索引比不加索引使用全表扫描还慢, 上网查, 据说是因为需要回表, 因为没有用到 using index(覆盖索引), 而回表查询是随机 ...

  10. 也给我的E420拆机清清灰尘

    用了两年,天气燥热,是得拆开清理下了,E430清理非常方便,拆开后面挡板就行,E420就麻烦很多,需要全部拆下,关于E420的拆机网上已经有非常详细的教程了,我这里做一些补充,有兴趣的同学欢迎参考. ...