#执行流程
SQL执行的流程如下图
graph TD
A[SqlSession] --> B[Executor]
B --> C[StatementHandler]
C --> D[ParameterHandler]
D --> E[Statement]
E --> F[数据库]
F --> G[ResultSet]
G --> H[ResultSetHandler]
H --> C
C --> B
B --> A
比较难受优快云的md竟然不能画流程图
根据上图可以看出来,整个流程涉及的模块大概有
- SqlSession:sql会话
- Executor:执行器
- StatementHandler:Statement 处理器
- ParameterHandler:参数处理器
- ResultSet:结果集
- ResultSetHandler:结果处理器
不过ParameterHandler参数处理器在进行SQL初始化的时候我们已经知道了,其主要逻辑是获取请求参数,对SQL中的?占位符进行替换处理。所以关于SQL执行我们主要学习的是:
- SqlSession
- Executor
- StatementHandler
- ResultSet和ResultSetHandler
SqlSessionFactory
我们先看SqlSession的工厂方法
/**
* Creates an {@link SqlSession} out of a connection or a DataSource
* 数据会话工厂接口
* @author Clinton Begin
*/
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
DefaultSqlSessionFactory是其主要的实现类,当然还有一个SqlSessionManager这个下面说
其核心的方法主要有两个
// 从数据源中获得会话
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);
// 返回要给默认的SQL会话
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();
}
}
// 从连接中获得会话
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
// 获得连接
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
// 和openSessionFromDataSource 类似
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
代码不算太难,主要逻辑差异不大,无非是一个从数据源中获得事务,一个是从连接中获得事务,然后创建一个默认的SqlSession
SqlSession
我们再看SqlSession
接口代码
/**
* The primary Java interface for working with MyBatis.
* Through this interface you can execute commands, get mappers and manage transactions.
* 数据会话
* @author Clinton Begin
*/
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
<T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter);
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);
void commit();
void commit(boolean force);
void rollback();
void rollback(boolean force);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> type);
Connection getConnection();
}
从上面方法的名称和继承关系我们可以大致了解几点:
- 接口继承了Closeable,提供了某些资源关闭的功能
- 主要方法涉及各种数据库操作的请求
- 提供的获得各种资源(系统配置,SQL的Mapper)
- 提供的获得连接和关闭连接功能
- 提供了事务的部分功能
- 提供了缓存操作功能
其主要实现类
- DefaultSqlSession
- SqlSessionManager
DefaultSqlSession
简单的介绍下里面的方法
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 获得mapped的selectList对象,然后执行查询
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
几乎所有的查询逻辑最后都会调用到这个方法。
整个逻辑就是从配置中获得statement对应的MappedStatement对象,然后通过执行器执行操作,然后将结果封装成符合要求的对象集合。
可以看下update、delete其实内部逻辑大同小异,不算太复杂。
SqlSessionManager
SqlSessionManager实现了SqlSessionFactory和SqlSession接口,但是这两个接口的内部逻辑实现,其实都是其内部的两个代理类来实现的
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
// 线程变量,显示当前线程的sql会话
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
// 创建代理对象
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
}