这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战
时序图
sequenceDiagram
participant A as DefaultSqlSessionFactory
participant B as Configuration
A ->> A : openSessionFromDataSource():DefaultSqlSession
A ->> B : newExecutor
B -->> A : Executor
详细步骤
DefaultSqlSessionFactory#openSessionFromDataSource
/**
* 从数据源中获取SqlSession对象
* @param execType 执行器类型,默认是在Configuration中定义的SIMPLE类型
* @param level 事务隔离级别
* @param autoCommit 是否自动提交事务
* @return SqlSession对象
*/
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);
// 创建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
/**
* 创建一个执行器
* @param transaction 事务
* @param executorType 数据库操作类型
* @return 执行器
*/
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor 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);
}
// 根据配置文件中的 settings 节点cacheEnabled配置项确定是否启用缓存
if (cacheEnabled) { // 如果配置启用该缓存
// 使用CachingExecutor装饰实际的执行器
executor = new CachingExecutor(executor);
}
// 为执行器增加拦截器(插件),以启用各个拦截器的功能
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
四种Executor
BatchExecutor
- 批量执行SQL
- 调用方法时,将待执行的
PreparedStatement通过addBatch方法加入
@Override
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
...
// addBatch
handler.batch(stmt);
return BATCH_UPDATE_RETURN_VALUE;
}
- 调用
SqlSession的commit方法时执行批量操作
sequenceDiagram
autonumber
participant A as DefaultSqlSession
participant B as BaseExecutor
participant C as BatchExecutor
participant D as Statement
A ->> B : commit
B ->> B : flushStatements
B ->> C : doFlushStatements
C ->> D : executeBatch:批量操作
SimpleExecutor
- 每次请求都会重新创建
PreparedStatement
ReuseExecutor
- 做了sql与PreparedStatement的缓存
- 请求时会判断是否存在缓存,不存在则创建PreparedStatement,否则从缓存中拿PreparedStatement
- 请求完成后不会关闭PreparedStatement,而是会进行缓存
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
if (hasStatementFor(sql)) { // 判断是否有缓存
stmt = getStatement(sql);
applyTransactionTimeout(stmt);
} else {
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
putStatement(sql, stmt); // 缓存sql与PreparedStatement
}
handler.parameterize(stmt);
return stmt;
}
CachingExecutor
- 与二级缓存有关,如果开启了二级缓存的全局开关,则会将获取的
Executor使用此对象进行包装
以上便是Mybatis创建SqlSession对象的过程,以及对四种
Executor的简单介绍。