引言

SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

1
2
3
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

上面是官方文档的内容:MyBatis官方文档|入门

在上一篇文章分析MyBatis执行SQL的时候,遗留了一些关于SqlSession的疑问,怎么创建,怎么释放。
SqlSessionTemplate的SqlSessionInterceptor中解决了上面的疑问:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}

1、SqlSession的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 从Spring事务管理器获取SqlSession,或者在需要时创建一个新的SqlSession。
* 试图从当前事务中获取SqlSession。如果没有,则创建一个新的。
* 然后,如果Spring TX是活动的,并且将SpringManagedTransactionFactory配置为事务管理器,则它将SqlSession与事务同步。
*
* @param sessionFactory 创建新会话的MyBatis {@code SqlSessionFactory}
* @param executorType 要创建的SqlSession的执行器类型
* @param exceptionTranslator 可选的。将SqlSession.commit()异常转换为Spring异常。
* @throws TransientDataAccessResourceException 如果事务是活动的,并且{@code SqlSessionFactory}没有使用{@code SpringManagedTransactionFactory}
* @see SpringManagedTransactionFactory
*/
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

//检索绑定到当前线程的给定键的资源。
//获取SqlSessionHolder
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

//从SqlSessionHolder中获取SqlSession
SqlSession session = sessionHolder(executorType, holder);
//如果存在就返回
if (session != null) {
return session;
}

if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Creating a new SqlSession");
}

//不存在就新建一个
session = sessionFactory.openSession(executorType);

//注册SqlSession到SqlSessionHolder
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

//返回新建的SqlSession
return session;
}

SqlSessionUtils中的方法,首先从SqlSessionHolder中获取SqlSession,如果获取失败,则创建一个新的。
这里着重看sessionFactory.openSession(executorType),DefaultSqlSessionFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
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();
}
}

方法入参:execType为SIMPLE,level为null,autoCommit为false。
首先获取Environment,在获取TransactionFactory,之后获取Transaction和Executor,最后返回DefaultSqlSession。

1.1、获取的TransactionFactory是什么时候设置的

1
2
3
4
5
6
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}

如果未配置TransactionFactory,则返回ManagedTransactionFactory,否则返回配置的TransactionFactory。
什么时候配置的呢?在分析SqlSessionFactoryBean的创建时有一段代码:

1
2
3
4
 if (this.transactionFactory == null) {
this.transactionFactory = new SpringManagedTransactionFactory();
}
configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));

即默认使用的是SpringManagedTransactionFactory。

1.2、newTransaction

1
2
3
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
return new SpringManagedTransaction(dataSource);
}

新建事务,这里DataSource为手动配置的com.zaxxer.hikari.HikariDataSource。另外两个参数没有使用,都是使用的数据源配置

1.3、newExecutor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}

新建SQL执行器,因为我的例子是SimpleExecutor,且使用了缓存,所以最后返回的是CachingExecutor,使用了装饰者模式。

2、SqlSession的关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 检查作为参数传递的{@code SqlSession}是否由Spring {@code TransactionSynchronizationManager}管理;
* 如果不是,则关闭它;否则,它只更新引用计数器,并让Spring在托管事务结束时调用close回调函数
*
* @param session
* @param sessionFactory
*/
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);

//SqlSessionHolder
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if ((holder != null) && (holder.getSqlSession() == session)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
}
//释放
holder.released();
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
}
//关闭session
session.close();
}
}

tencent.jpg