在Executor的解析一篇中我已经大致的分析了SqlSessionFactory对于创建SqlSession的工作,现在来进一步的探讨一下SqlSessionFactory的全部内容。
回顾之前的研究,已经知道SqlSessionFactory的一部分工作是创建SqlSession,SqlSessionFactory是一个接口,这个接口限定openSession返回的session必需是从连接或数据源创建的:
/**
* Creates an {@link SqlSession} out of a connection or a DataSource
* //创建一个必需是从连接或数据源创建的SqlSession
* @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,了解他是如何创建SqlSession的。Sqlsession不负责创建executor,那么executor也是由factory负责创建并传入给session的。创建session都是通过下面两个核心方法产生,一个通过数据源产生,另一个直接由连接对象产生,其实大同小异,数据源只是对连接做了一个封装而已。关键是根据传入的executor类型参数来决定创建哪一种executor,而他们最终都是创建DefaultSqlSession并返回:
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);//传入类型创建executor
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一些低级的DB驱动或者DB可能不支持事务,也就是只能必需提交,为应对这些情况设置为true
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);//传入类型创建executor
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
参考SqlSession的族系模式,这个DefaultSqlSessionFactory也是基础实现,而SqlSessionManager在之前解读SqlSession的时候出现的,它同时还持有一个DefaultSqlSessionFactory,也就是对DefaultSqlSessionFactory的一个包装。根据我上面接口中给出的注释,这个SqlSessionManager同时实现session和factory接口,是为了给用户提供方便,可以直接指定使用Executor的类型,而是整合了SqlSession和SqlSessionFactory的方法。
在实际中,我们可以这样使用SqlSessionManager来方便使用:
public int update(int id) throws IOException {
SqlSessionManager manager = SqlSessionManager.newInstance(Resources.getResourceAsReader("com/config/mybatis-config.xml"));
manager.startManagedSession(ExecutorType.REUSE);//创建指定类型的Executor包含在SqlSession内
int i = manager.update(namespace+"updateOne",id);//此时的manager就是一个session
manager.commit();
manager.close();
return i;
}
同时此时使用的session是线程安全的,我在第一篇SqlSession中讲到,这里就不再重复。另外需要注意的一点,如果通过下面的方式开启session,那么这个session是新建的非线程安全,因为manager又是factory,通过factory的方法创建session:
SqlSession session = manager.openSession();
并且它作为factory是不能保证factory单例的:
public static SqlSessionManager newInstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
前面说了这么多,终于轮到研究SqlSessionFactory是怎么来的了,SqlSessionManager是扩展的用户管理类,和mybatis其实关系不大,关键是DefaultSqlSessionFactory,它的创建很简单,通过SqlSessionFactoryBuilder的build方法来创建:
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);//解析配置文件
return build(parser.parse());//调用SqlSessionFactory构造方法创建factory
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
这就是我们熟知的起手方法了:
static{
String resource = "com/config/mybatis-config.xml";
try {
sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
最后总结一下,SqlSessionFactory是一个接口,它限定了创建session接口实现的方法,这些方法分为系统使用和用户扩展,SqlSessionManager既实现SqlSessionFactory接口,又实现了SqlSession接口,它是一个扩展用户管理类,可以直接创建所需类型的executor并执行查询。DefaultSqlSessionFactory是SqlSessionFactory的实现子类,实现了Session的创建基础方法,通过SqlSessionFactoryBuilder来创建DefaultSqlSessionFactory即可得到SqlSessionFactory并创建SqlSession。
结构图如下: