1、SqlSession的构建过程
在上一章,详细的介绍了SqlSessionFactory的构建过程,它是用来获取SqlSession对象的,所以本章节就主要讲述SqlSession的构建过程。
程序代码的入口:
我们知道SqlSession对象是通过SqlSessionFactory的openSession()方法获取的,所以我们先来看一下SqlSessionFactory接口中的方法:
可以发现SqlSessionFactory接口提供一系列重载的openSession方法,其参数如下(这些参数的意义会在后面介绍):
- boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
- Connection:提供连接。
- TransactionIsolationLevel:定义事务隔离级别。
- ExecutorType:定义执行器类型。
SqlSessionFactory接口的实现类为DefaultSqlSessionFactory类。所以我们去DefaultSqlSessionFactory实现类中查看重写的openSession()方法:
//以无参的openSession()方法为例 public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
通过查看其它重写的方法,会发现最终都调用了openSessionFromDataSource方法,所以继续进入方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取Configration全局配置中的environment的配置 final Environment environment = configuration.getEnvironment(); // 通过environment配置构建transactionFactory对象 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 从工厂中获取一个事务实例 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 通过configuration构建Executor执行器对象 final Executor executor = configuration.newExecutor(tx, execType); // 返回SqlSession的默认实现类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(); } }
上面代码中有一行是通过configuration.newExecutor(tx,execType)来构建Executor执行器对象,这一步非常重要,因为MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 来执行的,它负责SQL语句的生成和查询缓存的维护 。所以我们看一下它是怎么创建的,这里调用了Configuration类中newExecutor()方法。
// ====== Configuration 类中的方法 ====== public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 定义Executor执行器 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 { // 如果没有配置,默认就为SimpleExecutor executor = new SimpleExecutor(this, transaction); } //如果开启了二级缓存,则使用CachingExecutor 来包装executor, //在查询之前都会先查询缓存中是否有对应的数据,包装的过程使用了装饰者模式 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 最后使用每个拦截器重新包装executor并返回 executor = (Executor) interceptorChain.pluginAll(executor); //返回创建好的Executor执行器 return executor; }
注意(这里了解就好):executor = (Executor) interceptorChain.pluginAll(executor);这个是Mybatis中的插件,它将构建一层层的代理对象,可以在执行真正的Executor的方法前,执行配置在插件中的方法对核心代码进行修改,所以不要轻易使用插件,这里用的是责任链模式。Mybatis在实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler四大接口对象的时候都是调用interceptorChain.pluginAll() 方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法。
Executor 对象创建完之后会以参数的形式传入DefaultSqlSession的构造方法中,从而完成SqlSession对象的创建并且返回。
至此SqlSession对象的创建过程也就结束了。
SqlSession对象构建过程中的时序图:
2、重载的openSession方法参数介绍
上面程序入口我们调用的是无参数的openSession()方法,那么其它重载的方法有什么用呢?这里来介绍一下有参方法中的参数含义,有四类分别为。
- boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
- Connection:提供连接。
- TransactionIsolationLevel:定义事务隔离级别。
- ExecutorType:定义执行器类型。
①、boolean autoCommit:是否自动提交事物,默认为false。
如果为true就自动提交事务,后面就不要写commit()方法提交了。
②、TransactionIsolationLevel :事务隔离级别类,它是一个枚举类型。
可以发现默认五种隔离级别:
- 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):可串行化
③、Connection:提供连接对象。
如果使用这种方式会优先使用这里面的数据库连接对象。如:
④、ExecutorType :执行器类型,它是一个枚举类型。
它主要用来判断使用哪种类型的执行器Executor,因为SqlSession是真正来执行Java与数据库交互的对象,提供了查询(query)、更新(update)等方法,主要有三种类型:
- SIMPLE:简易执行器,如果不配置类型,就是默认执行器
- REUSE:能过执行重用预处理语句的执行器
- BATCH:执行器重用语句和批量更新,批量专用的执行
在上面创建Executor执行器的代码中已经进行了判断。所以这里就不再多说了。
-------------------------------------------------------------------------