mybatis源码分析3 - sqlSession的创建
2018-01-09 12:03
591 查看
1 引言和主要类
初始化mybatis,也就是创建完单例SqlSessionFactory后,就进入到了mybatis的运行阶段。mybatis每次的运行都是通过SqlSession对象来进行,它是运行时的核心。不同于SqlSessionFactory,SqlSession不是线程安全的,故一般建议放在局部作用域中定义, 且使用完后close掉。我们使用mybatis创建SqlSession十分简单,代码如下// 读入xml配置文件 String resource = "main/resources/SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 创建SqlSessionFactory,初始化mybatis的关键所在,上一节分析过了 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 利用SqlSessionFactory来创建SqlSession,这一节重点分析 SqlSession session = sessionFactory.openSession();
创建SqlSession十分简单,调用SqlSessionFactory的openSession()方法即可。但这个方法背后其实相当复杂,mybatis为我们做了很多幕后工作。我们先介绍下openSession()过程中要用到的主要类。
DefaultSqlSessionFactory:SqlSessionFactory的默认实现类,上一节我们讲到过。
Transaction:数据库事务,有JdbcTransaction和ManagedTransaction两个实现
Executor:调度器,sqlSession的select update等方法的真正实现,mybatis运行的核心。
DefaultSqlSession:sqlSession的默认实现类,其方法几乎均由Executor代理实现。
2 流程分析
我们从DefaultSqlSessionFactory这个默认工厂类的openSession()方法说起。// SqlSessionFactory单例创建并开启一个sqlSession实例。sqlSession线程不安全,一般存放在局部作用域中,用完close即可。 public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } // 开启sqlSession private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取configuration的environment,它代表了运行的数据库环境, // 由配置文件中的environments节点的environment子节点生成,创建SqlSessionFactory时指定其id,默认为default final Environment environment = configuration.getEnvironment(); // environment实例中取出transactionFactory成员变量,然后实例化它。 // JdbcTransactionFactory创建JdbcTransaction,使用JDBC代理管理commit等事务 // ManagedTransactionFactory创建ManagedTransaction,自身不对事务进行处理,完全交给容器,如Spring final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 由事务transaction创建调度器Executor,SqlSession的几乎所有方法都是通过代理模式由Executor真正实现 // Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称SqlSession四大组件 // ExecutorType在XML配置文件的settings节点中设置(defaultExecutorType), 可以取SIMPLE REUSE BATCH,默认为SIMPLE // SIMPLE表示简易执行器,REUSE为一种执行器重用预处理语句,BATCH则为批量专用的执行器。 final Executor executor = configuration.newExecutor(tx, execType); // 构造SqlSession实例,mybatis默认的实现类为DefaultSqlSession 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(); } }
mybatis先由初始化阶段创建在configuration中的environment变量来创建数据库事务,然后根据XML配置文件的settings节点中设置的defaultExecutorType来创建调度器Executor,最后就可以创建得到DefaultSqlSession实例了。下面我们来分析事务的创建
2.1 数据库事务Transaction的创建
Transaction有两个实现类,即JdbcTransaction和ManagedTransaction,他们分别由JdbcTransactionFactory和ManagedTransactionFactory工厂类来创建实例。JdbcTransaction本地事务由数据库本身来管理事务,其getConnection()从DataSource中得到, commit() rollback() close() 则由java.sql.Connection实例代理实现。ManagedTransaction由容器来管理事务,其getConnection()从DataSource中得到,commit() rollback()均为空实现,不做任何事情,完全托管给容器。
下面以JDBCTransaction为例来看Transaction事务的创建
// 工厂类来创建事务实例 // @Param DataSource: 数据库源 // @Param level: 事务隔离级别,定义并发事务的处理方式。如A读时,B在写。 // @param autoCommit: 是否自动提交 public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) { return new JdbcTransaction(ds, level, autoCommit); }
2.2 调度器Executor的创建
Executor是SqlSession的核心,其select update commit rollback close等方法均由Executor代理实现。Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称mybatis运行时四大组件。四大组件均可由用户通过插件注入,也都有默认实现。下面看创建Executor的源码// 创建sqlsession执行器Executor public Executor newExecutor(Transaction transaction, ExecutorType executorType) { // executorType通过settings节点中的defaultExecutorType来设置,没有设置则默认为SIMPLE executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; // 根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor 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); } // 如果打开了缓存,使用CachingExecutor包装下之前创建的executor,简单理解就是为executor添加了cache功能 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 将执行器executor设置到plugins节点中设置的所有插件中,作为插件的目标执行器。 executor = (Executor) interceptorChain.pluginAll(executor); return executor; } public Object pluginAll(Object target) { // 遍历所有插件,将传入的target,作为插件的目标执行器。插件通过配置XML文件的plugins节点设置。 for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; }
Executor根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor三个实现类,他们的基类为BaseExecutor。下一节我们分析selectList方法时,以SimpleExecutor这个默认的调度器为例分析。
2.3 SqlSession实例的创建
SqlSession的默认实现为DefaultSqlSession,其创建十分简单,构造方法如下public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; }
其中executor成员最为关键,DefaultSqlSession的大部分方法均是通过它来代理实现。比如select update方法。而delete和insert方法均调用update方法来实现。
// select方法通过executor实现,典型的代理模式 // selectOne selectList均调用它实现 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { MappedStatement ms = configuration.getMappedStatement(statement); // 利用调度器Executor代理实现 executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } // update方法通过executor实现,典型的代理模式 // insert update等DML操作均调用它实现 public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement); // 利用调度器Executor代理实现 return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } public int insert(String statement, Object parameter) { return update(statement, parameter); } public int delete(String statement, Object parameter) { return update(statement, parameter); }
3 总结
构建SqlSession的核心是创建调度器Executor,它是mybatis运行的核心。通过调度StatementHandler ParameterHandler ResultSetHandler来完成各种操作。四者合称SqlSession四大组件。后面一节我们以sqlSession.selectOne()方法为例来分析mybatis的CRUD操作的背后原理。相关文章
mybatis源码分析1 - 框架mybatis源码分析2 - SqlSessionFactory的创建
mybatis源码分析3 - sqlSession的创建
mybatis源码分析4 - sqlSession读写数据库完全解析
mybatis源码分析5 - mapper读写数据库完全解析
mybatis源码分析6 - mybatis-spring容器初始化
mybatis源码分析7 - mybatis-spring读写数据库全过程
相关文章推荐
- Mybatis3源码分析(09)-SqlSession创建及简要说明
- mybatis源码学习之执行过程分析(1)——SqlSessionFactory及SqlSession的创建
- mybatis源码分析(1)-----sqlSessionFactory创建
- 【Mybatis源码分析】01-SqlSessionFactory的创建过程
- Mybatis源码(二)之Spring整合mybatis创建SqlSession
- MyBatis 源码分析——SqlSession接口和Executor类
- mybatis源码分析之SqlSession的创建过程
- MyBatis运行原理(二)SqlSession对象创建过程分析
- mybatis源码分析(一,sqlSessionFactory的创建流程)
- MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析
- MyBatis 源码分析——SqlSession接口和Executor类
- Mybatis架构设计及源码分析-SqlSession
- Mybatis 源码分析一、 SqlSessionFactory的创建过程
- mybatis源码分析4 - sqlSession读写数据库完全解析
- MyBatis-3.4.2-源码分析16:XML解析之SqlSessionFactory|SqlSession
- Mybatis源码分析之SqlSessionFactory,SqlSession和连接池
- MyBatis 事务源码分析
- rxJava的使用--Observable的创建及源码分析(二)
- MyBatis源码分析——Cache构建以及应用
- MyBatis源码分析