Mybatis 源码(五):SqlSession对象构建
SqlSession对象创建核心在SQL执行器Executor对象的创建,sqlSession持有Executor对象。
1、SqlSession对象的创建
应用程序每次操作数据库,都需要创建一个sqlSession对象,通过sqlSession完成SQL语句的执行。下面来看看sqlSession的创建过程。
// 获取sqlSession SqlSession sqlSession = sqlSessionFactory.openSession();
1.1、SqlSessionFactory默认实现子类
SqlSesiionFactory的类图如下:
![0](https://img2023.cnblogs.com/blog/1680081/202303/1680081-20230320181321553-1386747259.png)
SqlSessionFactory有两个子类DefaultSqlSessionFactory、SqlSessionManager,Mybatis默认使用DefaultSqlSessionFactory的openSession()方法创建sqlSession对象。
1.2、openSession()
创建数据库连接会话对象,DefaultSqlSessionFactory#openSession() 核心代码
1 // 获取数据库的会话,创建出数据库连接的会话对象SqlSession 2 public SqlSession openSession() { 3 // 从数据源中获取sqlSession 4 return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); 5 }
1.3、openSessionFromDataSource()
从数据源中获取sqlSession,DefaultSqlSessionFactory#openSessionFromDataSource() 核心代码:
1 // 从数据源中获取会话对象 -> sqlSession 2 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { 3 Transaction tx = null; 4 try { 5 // 获取mybatis-config.xml配置文件中配置的Environment对象, 6 final Environment environment = configuration.getEnvironment(); 7 // 获取TransactionFactory对象 8 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 9 // 创建Transaction对象 10 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 11 // 根据配置创建Executor对象 12 final Executor executor = configuration.newExecutor(tx, execType); 13 //然后产生一个DefaultSqlSession 14 return new DefaultSqlSession(configuration, executor, autoCommit); 15 } catch (Exception e) { 16 //如果打开事务出错,则关闭它 17 closeTransaction(tx); // may have fetched a connection so lets call close() 18 throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); 19 } finally { 20 //最后清空错误上下文 21 ErrorContext.instance().reset(); 22 } 23 }
1、获取事务对象transaction
1.1、获取事务工厂对象transactionFactory
获取配置类configuration中的environment环境属性,有关environment的配置解析,详见Mybatis 源码(三):Mybatis配置解析。
environment环境中持有事务工厂TransactionFactory、数据源DataSource。解析environmet配置时的核心代码段如下:
![](https://img2023.cnblogs.com/blog/1680081/202303/1680081-20230320180217870-970283938.png)
根据全局配置,从环境配置中获取事务工厂JdbcTransactionFactory,DefaultSqlSessionFactory#getTransactionFactoryFromEnvironment() 核心代码:
1 // 从环境配置中获取事务工厂 2 private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) { 3 //如果没有配置事务工厂,则返回托管事务工厂 4 if (environment == null || environment.getTransactionFactory() == null) { 5 return new ManagedTransactionFactory(); 6 } 7 // 返回配置的事务工厂 8 return environment.getTransactionFactory(); 9 }
1.2、创建事务对象transaction
根据事务工厂创建事务对象transaction,根据全局配置创建的是JdbcTransaction,JdbcTransactionFactory#newTransaction() 核心代码
1 public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) { 2 return new JdbcTransaction(ds, level, autoCommit); 3 }
2、创建执行器Executor对象
创建执行器对象Executor, Configuration#newExecutor(Transaction transaction, ExecutorType executorType) 核心代码:
1 // 创建执行器 2 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { 3 executorType = executorType == null ? defaultExecutorType : executorType; 4 executorType = executorType == null ? ExecutorType.SIMPLE : executorType; 5 Executor executor; 6 // 根据参数,选择合适的Executor实现 7 if (ExecutorType.BATCH == executorType) { 8 executor = new BatchExecutor(this, transaction); 9 } else if (ExecutorType.REUSE == executorType) { 10 executor = new ReuseExecutor(this, transaction); 11 } else { 12 executor = new SimpleExecutor(this, transaction); 13 } 14 // 根据配置决定是否开启二级缓存的功能 15 if (cacheEnabled) { 16 executor = new CachingExecutor(executor); 17 } 18 // 此处调用插件,通过插件可以改变Executor行为 19 executor = (Executor) interceptorChain.pluginAll(executor); 20 return executor; 21 }
1、newExecutor方法参数
newExecutor方法有两个参数,Transaction参数通过configuration中的environment属性持有的事务工厂创建的JdbcTransaction。
ExecutorType参数是Mybtais中默认的执行器类型,通过DefaultSqlSessionFactory#openSession()方法进行传递。
1 public SqlSession openSession() { 2 // 从数据源中获取会话对象 3 return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); 4 }
Mybatis中默认执行器类型ExecutorType.SIMPLE,配置类中configuration的defaultExecutorType属性:
// 默认简单执行器 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
执行器ExecutorType枚举,最常用的执行器类型是Simple。
1 /** 2 * SIMPLE 为每个语句的执行创建一个新的预处理语句。 3 * REUSE 复用预处理语句 4 * BATCH 批量执行所有更新语句 5 */ 6 public enum ExecutorType { 7 SIMPLE, REUSE, BATCH 8 }
2、根据执行器类型,创建不同的SQL执行器
根据不同的执行器类型,创建不同Executor执行器,Executor执行器中持有Configuration配置对象、Transaction事务对象。
执行器Executor接口类图如下:
![](https://img2023.cnblogs.com/blog/1680081/202303/1680081-20230320180704458-1803206393.png)
执行器类型ExecutorType枚举中,分别对应SimpleExecutor、BatchExecutor、ReuseExecutor,都继承自Executor接口,Executor接口详情:
1 // 执行器 2 public interface Executor { 3 4 // 不需要ResultHandler 5 ResultHandler NO_RESULT_HANDLER = null; 6 7 // 执行insert、delete、update三种类型的SQL语句 8 int update(MappedStatement ms, Object parameter) throws SQLException; 9 10 // 执行select类型的SQL语句,返回值分为结果对象列表或游标对象 11 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; 12 13 // 查询,带分页 14 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; 15 16 <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException; 17 18 // 批量执行SQL语句 19 List<BatchResult> flushStatements() throws SQLException; 20 21 // 提交事务 22 void commit(boolean required) throws SQLException; 23 24 // 回滚事务 25 void rollback(boolean required) throws SQLException; 26 27 // 创建缓存中用到的CacheKey对象 28 CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); 29 30 // 根据CacheKey对象查找缓存 31 boolean isCached(MappedStatement ms, CacheKey key); 32 33 // 清空一级缓存 34 void clearLocalCache(); 35 36 // 延迟加载一级缓存中的数据 37 void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType); 38 39 // 获取事务对象 40 Transaction getTransaction(); 41 42 // 关闭Executor对象 43 void close(boolean forceRollback); 44 45 // 检测Executor是否已关闭 46 boolean isClosed(); 47 48 void setExecutorWrapper(Executor executor); 49 }
Executor执行器主要完成SQL的执行操作,也包含对事务、缓存的处理。
3、缓存的处理
从configuration配置类是否开启缓存配置,默认开启。可在标签中设置缓存是否开启。
// 开启缓存标识 protected boolean cacheEnabled = true;
若缓存开启,创建缓存执行器CachingExecutor, 持有SimpleExecutor等执行器,事务缓存管理器TransactionalCacheManager对象。
1 public class CachingExecutor implements Executor { 2 3 private final Executor delegate; 4 private final TransactionalCacheManager tcm = new TransactionalCacheManager(); 5 6 public CachingExecutor(Executor delegate) { 7 this.delegate = delegate; 8 delegate.setExecutorWrapper(this); 9 } 10 // ... 11 }
CachingExecutor详情如下:
![](https://img2023.cnblogs.com/blog/1680081/202303/1680081-20230320180927909-1687645643.png)
3、创建SqlSession
DefaultSqLSession构造函数:
1 // configuration配置对象 2 private final Configuration configuration; 3 // 底层依赖的Executor对象 4 private final Executor executor; 5 // 是否自动提交 6 private final boolean autoCommit; 7 // 当前缓存中是否有脏数据 8 private boolean dirty; 9 10 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { 11 this.configuration = configuration; 12 this.executor = executor; 13 this.dirty = false; 14 this.autoCommit = autoCommit; 15 }
2、核心流程图
创建sqlSession对象核心流程如下:
3、总结
sqlSession对象的创建过程中,最重要的是创建了SQL执行器Executor对象,主要步骤:
1、Executor对象创建前的准备 - 创建事务对象
创建Executor需要事务对象,通过configuration中environment属性获取事务工厂创建事务对象。
2、创建Executor对象 - 根据执行器类型、是否开启缓存创建不同的Executor
2.1、根据不同的执行器类型创建不同的Executor对象(simple/reuse/batch);
2.2、判断是否开启缓存,若开启缓存,创建缓存执行器CachingExecutor封装SimpleExecutor/ReuseExecutor/BatchExecutor对象。
3、创建SqlSession对象
创建sqlSession对象,持有Executor对象。