d前面介绍 DefaultSqlSessionFactory 可以获取操作SQL的 session实例。
从下面的代码可以看出,每次调用openSession 的时候,都会创建一个新的DefaultSession的实例。
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();
}
}
SqlSessionManager是对 DefaultSqlSessionFactory的一个封装。
public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionManager(sqlSessionFactory);
}
写错了吧?怎么是 SqlSessionManager 封装 SqlSessionFactory, SqlSessionManager是管理session的吧!
没错!
来看个图:
SqlSessionFactoryBuilder 负责接收mybatis-config.xml的输入流,创建 DefaultSqlSessionFactory 实例。
DefaultSqlSessionFactory实现了 SqlSessionFactory 接口。
SqlSessionManager实现了SqlSessionFactory接口,又封装了 DefaultSqlSessionFactory。
Java的代理模式,或者装饰者模式!
与DefaultSqlSessionFactory不同的是,SqlSessionManager提供了一个本地线程变量,每当通过startManagedSession()获得session实例的时候,会在本地线程保存session实例。这是其一不同。
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
其二,SqlSessionManager 实现了Session接口。意味着,SqlSessionManager集成了 sqlSessionFactory和session 的功能。通过SqlSessionManager,开发者可以不在理会SqlSessionFacotry的存在,直接面向Session编程。
SqlSessionManager 内部提供了一个sqlSessionProxy,这个sqlSessionProxy提供了所有Session接口的实现,而实现中正是使用了上面提到的本地线程保存的session实例。
这样,在同一个线程实现不同的sql操作,可以复用本地线程session,避免了DefaultSqlSessionFactory实现的每一个sql操作都要创建新的session实例。