mybatis-SqlSession
Posted siye1989
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis-SqlSession相关的知识,希望对你有一定的参考价值。
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;
-
<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 |