1. 概述
在前面,我们已经详细解析了 MyBatis 执行器 Executor 相关的内容,但是显然,Executor 是不适合直接暴露给用户使用的,而是需要通过 SqlSession 。
流程如下图:
示例代码如下:
// 仅仅是示例哈 |
而本文解析的类,都在 session
包下,整体类图如下:
老艿艿:省略了一部分前面已经解析过的类。
- 核心是 SqlSession 。
- SqlSessionFactory ,负责创建 SqlSession 对象的工厂。
- SqlSessionFactoryBuilder ,是 SqlSessionFactory 的构建器。
下面,我们按照 SqlSessionFactoryBuilder => SqlSessionFactory => SqlSession 来详细解析。
2. SqlSessionFactoryBuilder
org.apache.ibatis.session.SqlSessionFactoryBuilder
,SqlSessionFactory 构造器。代码如下:
// SqlSessionFactory.java |
- 提供了各种 build 的重载方法,核心的套路都是解析出 Configuration 配置对象,从而创建出 DefaultSqlSessionFactory 对象。
3. SqlSessionFactory
org.apache.ibatis.session.SqlSessionFactory
,SqlSession 工厂接口。代码如下:
// SqlSessionFactory.java |
- 定义了
#openSession(...)
和#getConfiguration()
两类方法。
3.1 DefaultSqlSessionFactory
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
,实现 SqlSessionFactory 接口,默认的 SqlSessionFactory 实现类。
3.1.1 构造方法
// DefaultSqlSessionFactory.java |
3.1.2 openSession
// DefaultSqlSessionFactory.java |
-
调用
#openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)
方法,获得 SqlSession 对象。代码如下:// DefaultSqlSessionFactory.java
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获得 Environment 对象
final Environment environment = configuration.getEnvironment();
// 创建 Transaction 对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建 Executor 对象
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// 如果发生异常,则关闭 Transaction 对象
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " e, e);
} finally {
ErrorContext.instance().reset();
}
}- DefaultSqlSession 的创建,需要
configuration
、executor
、autoCommit
三个参数。
- DefaultSqlSession 的创建,需要
-
#openSessionFromConnection(ExecutorType execType, Connection connection)
方法,获得 SqlSession 对象。代码如下:// DefaultSqlSessionFactory.java
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;
}
// 获得 Environment 对象
final Environment environment = configuration.getEnvironment();
// 创建 Transaction 对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
// 创建 Executor 对象
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " e, e);
} finally {
ErrorContext.instance().reset();
}
}
3.1.3 getTransactionFactoryFromEnvironment
// DefaultSqlSessionFactory.java |
3.1.4 closeTransaction
// DefaultSqlSessionFactory.java |
4. SqlSession
org.apache.ibatis.session.SqlSession
,SQL Session 接口。代码如下:
// SqlSession.java |
- 大体接口上,和 Executor 接口是相似的。
4.1 DefaultSqlSession
org.apache.ibatis.session.defaults.DefaultSqlSession
,实现 SqlSession 接口,默认的 SqlSession 实现类。
4.1.1 构造方法
// DefaultSqlSession.java |
4.1.2 selectList
// DefaultSqlSession.java |
-
<1>
处,调用Configuration#getMappedStatement(String id)
方法,获得 MappedStatement 对象。代码如下:// DefaultSqlSession.java
/**
* MappedStatement 映射
*
* KEY:`${namespace}.${id}`
*/
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<>("Mapped Statements collection");
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
// 校验,保证所有 MappedStatement 已经构造完毕
if (validateIncompleteStatements) {
buildAllStatements();
}
// 获取 MappedStatement 对象
return mappedStatements.get(id);
}
protected void buildAllStatements() {
if (!incompleteResultMaps.isEmpty()) {
synchronized (incompleteResultMaps) { // 保证 incompleteResultMaps 被解析完
// This always throws a BuilderException.
incompleteResultMaps.iterator().next().resolve();
}
}
if (!incompleteCacheRefs.isEmpty()) {
synchronized (incompleteCacheRefs) { // 保证 incompleteCacheRefs 被解析完
// This always throws a BuilderException.
incompleteCacheRefs.iterator().next().resolveCacheRef();
}
}
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) { // 保证 incompleteStatements 被解析完
// This always throws a BuilderException.
incompleteStatements.iterator().next().parseStatementNode();
}
}
if (!incompleteMethods.isEmpty()) {
synchronized (incompleteMethods) { // 保证 incompleteMethods 被解析完
// This always throws a BuilderException.
incompleteMethods.iterator().next().resolve();
}
}
}- 其中,
#buildAllStatements()
方法,是用来保证所有 MappedStatement 已经构造完毕。不过艿艿,暂时没想到,什么情况下,会出现 MappedStatement 没被正确构建的情况。猜测有可能是防御性编程。
- 其中,
-
<2>
处,调用Executor#query(...)
方法,执行查询。
4.1.3 selectOne
// DefaultSqlSession.java |
- 内部调用
#selectList(String statement, Object parameter)
方法,进行实现。
4.1.4 selectMap
#selectMap(...)
方法,查询结果,并基于 Map 聚合结果。代码如下:
// DefaultSqlSession.java |
-
<1>
处,调用#selectList(String statement, Object parameter, RowBounds rowBounds)
方法,执行查询。 -
<2>
处,创建 DefaultMapResultHandler 对象。 -
<3>
处,创建 DefaultResultContext 对象。 -
<4>
处,遍历查询结果,并调用DefaultMapResultHandler#handleResult(context)
方法,将结果的当前元素,聚合成 Map 。代码如下:// DefaultMapResultHandler.java
public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {
/**
* 结果,基于 Map 聚合
*/
private final Map<K, V> mappedResults;
/**
* {@link #mappedResults} 的 KEY 属性名
*/
private final String mapKey;
private final ObjectFactory objectFactory;
private final ObjectWrapperFactory objectWrapperFactory;
private final ReflectorFactory reflectorFactory;
@SuppressWarnings("unchecked")
public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
// 创建 Map 对象
this.mappedResults = objectFactory.create(Map.class);
this.mapKey = mapKey;
}
@Override
public void handleResult(ResultContext<? extends V> context) {
// 获得 KEY 对应的属性
final V value = context.getResultObject();
final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
// TODO is that assignment always true?
final K key = (K) mo.getValue(mapKey);
// 添加到 mappedResults 中
mappedResults.put(key, value);
}
public Map<K, V> getMappedResults() {
return mappedResults;
}
} -
<5>
处,返回结果。
4.1.5 selectCursor
// DefaultSqlSession.java |
-
<1>
处,调用Configuration#getMappedStatement(String id)
方法,获得 MappedStatement 对象。 -
<2>
处,调用Executor#queryCursor(...)
方法,执行查询。 -
<3>
处,调用#registerCursor(Cursor<T> cursor)
方法,添加cursor
到cursorList
中。代码如下:// DefaultSqlSession.java
private <T> void registerCursor(Cursor<T> cursor) {
if (cursorList == null) {
cursorList = new ArrayList<>();
}
cursorList.add(cursor);
}
4.1.6 select
#select(..., ResultHandler handler)
方法,执行查询,使用传入的 handler
方法参数,对结果进行处理。代码如下:
// DefaultSqlSession.java |
4.1.7 wrapCollection
在上述的查询方法中,我们都可以看到一个 #wrapCollection(final Object object)
方法,若参数 object
是 Collection、Array、Map 参数类型的情况下,包装成 Map 返回。代码如下:
// DefaultSqlSession.java |
4.1.8 update
// DefaultSqlSession.java |
-
<1>
处,标记dirty
,表示执行过写操作。该参数,会在事务的提交和回滚,产生其用途。 -
<2>
处,获得 MappedStatement 对象。 -
<3>
处,调用Executor#update(MappedStatement ms, Object parameter)
方法,执行更新操作。
4.1.9 insert
// DefaultSqlSession.java |
- 基于
#update(...)
方法来实现。
4.1.10 delete
// DefaultSqlSession.java |
- 基于
#update(...)
方法来实现。
4.1.11 flushStatements
#flushStatements()
方法,提交批处理。代码如下:
// DefaultSqlSession.java |
4.1.12 commit
// DefaultSqlSession.java |
-
其中,
#isCommitOrRollbackRequired(boolean force)
方法,判断是否执行提交或回滚。代码如下:// DefaultSqlSession.java
private boolean isCommitOrRollbackRequired(boolean force) {
return (!autoCommit && dirty) || force;
}- 有两种情况需要触发:
- 1)未开启自动提交,并且数据发生写操作
- 2)强制提交
4.1.13 rollback
// DefaultSqlSession.java |
4.1.14 close
#close()
方法,关闭会话。代码如下:
// DefaultSqlSession.java |
-
<1>
处,调用Executor#close(boolean forceRollback)
方法,关闭执行器。并且,根据forceRollback
参数,是否进行事务回滚。 -
<2>
处,调用#closeCursors()
方法,关闭所有游标。代码如下:// DefaultSqlSession.java
private void closeCursors() {
if (cursorList != null && cursorList.size() != 0) {
for (Cursor<?> cursor : cursorList) {
try {
cursor.close();
} catch (IOException e) {
throw ExceptionFactory.wrapException("Error closing cursor. Cause: " e, e);
}
}
cursorList.clear();
}
}
-
<3>
处,重置dirty
为false
。
4.1.15 getConfiguration
// DefaultSqlSession.java |
4.1.16 getMapper
// DefaultSqlSession.java |
4.1.17 getConnection
// DefaultSqlSession.java |
4.1.18 clearCache
// DefaultSqlSession.java |
5. SqlSessionManager
org.apache.ibatis.session.SqlSessionManager
,实现 SqlSessionFactory、SqlSession 接口,SqlSession 管理器。所以,从这里已经可以看出,SqlSessionManager 是 SqlSessionFactory 和 SqlSession 的职能相加。
5.1 构造方法
// SqlSessionManager.java |
- 比较有意思的有两点,我们逐条来看。
-
<1>
处,localSqlSession
属性,线程变量,记录当前线程的 SqlSession 对象。 -
<2>
处,创建 SqlSession 的代理对象,而方法的拦截器是 SqlSessionInterceptor 类。详细解析,见 「5.6 SqlSessionInterceptor」 。
5.2 newInstance
#newInstance(...)
静态方法,创建 SqlSessionManager 对象。代码如下:
// SqlSessionManager.java |
- 代码比较简单,胖友自己瞅瞅。
5.3 startManagedSession
#startManagedSession(...)
方法,发起一个可被管理的 SqlSession 。代码如下:
// SqlSessionManager.java |
- 可能胖友很难理解“可被管理”的 SqlSession 的意思?继续往下看。
5.4 对 SqlSessionFactory 的实现方法
// SqlSessionManager.java |
- 直接调用
sqlSessionFactory
对应的方法即可。
5.5 对 SqlSession 的实现方法
// SqlSessionManager.java |