1. SqlSessionFactory基本介绍
SqlSessionFactory是MyBatis框架中的一个接口,主要负责MyBatis框架初始化操作及为开发人员提供SqlSession对象。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,SqlSessionFactoryBuilder可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。
//通过openSession方法获得sqlSession
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);//事务是手动提交还是自动提交
SqlSession openSession(Connection 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();
}
openSession方法重载的目的主要是帮助开发人员根据自己的需要得到一个openSession
SqlSessionFactory有两个实现类:
- SqlSessionManager(被抛弃)
SqlSessionManager是用来进行线程安全控制的,看第三行代码,ThreadLocal是做线程安全的,把SqlSession放入了当前用户线程中。因为在实际开发中MyBatis是和Sring框架是一起用的,线程安全由Spring框架来处理了,所以它被抛弃了。
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
- DefaultSqlSessionFactory
直接看源码,看DefaultSqlSessionFactory结构可以看到它就一个属性Configuration,configuration在内存中存储了MyBatis框架中相关配置文件信息。
找到openSessionFromDataSource方法,里面有三个参数:
ExecutorType:执行器的类型。默认类型时simple
TransactionIsolationLevel:数据库隔离级别。
autoCommit:是否支持手动事务提交。
由于代码太多,直接看源码中的注释。
/**
* @author Clinton Begin
*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
//传入配置文件生成的对象
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
@Override
public SqlSession openSession() {
return
openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);//告诉我们如何去建一个sqlSssion
}
//autoCommit true支持事务 false不支持事务
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
@Override
public SqlSession openSession(ExecutorType execType) {
return openSessionFromDataSource(execType, null, false);
}
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
}
//执行类型,有4种,BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return openSessionFromDataSource(execType, level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
@Override
public SqlSession openSession(Connection connection) {
return
openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return openSessionFromConnection(execType, connection);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//读取环境变量(配置文件中<environment>标签里面内容)
final Environment environment = configuration.getEnvironment();
//通过环境变量获取当前事务的管理方式,配置文件中的transactionManager 元素配置的type来选择事务
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//事务管理对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//获取执行器
//execType是sql操作类型
//BatchExecutor用于执行批量sql操作
//ReuseExecutor会重用statement执行sql操作
//SimpleExecutor简单执行sql操作
//CachingExecutor 在查找数据库前先查找缓存,若没有找到的话调用delegate从数据库查询,并将查询结果存入缓存中。
final Executor executor = configuration.newExecutor(tx, execType);
//configuration, executor, autoCommit打包交给DefaultSqlSession(sqlSession实现类)
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
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);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//事务工厂,mybatis对于事务的管理有两种形式,
//使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
//使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,交给Spring来实现对事务的管理
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException ignore) {
// Intentionally ignore. Prefer previous error.
}
}
}
}
2. 创建SqlSessionFactory基本执行流程
调用 SqlSessionFactoryBuilder 对象的 build(inputStream) 方法;
SqlSessionFactoryBuilder 会根据输入流 inputStream 等信息创建XMLConfigBuilder 对象 ; Dom4j.jar
SqlSessionFactoryBuilder 调用 XMLConfigBuilder 对象的 parse() 方法;
XMLConfigBuilder 对象返回 Configuration 对象;
SqlSessionFactoryBuilder创建一个DefaultSessionFactory 对象,并将Configuration对象作为参数传给DefaultSessionFactory对象;
SqlSessionFactoryBuilder 返回 DefaultSessionFactory 对象给 Client ,供 Client使用。
Client可以使用DefaultSessionFactory对象创建需要的SqlSession.
public class SqlSessionFactoryBuilder {
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);//一个XML文档只能解析一次parsed否则抛异常
return build(parser.parse());
} 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.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
上面初始化过程中设计到几个对象:
- SqlSessionFactoryBuilder :SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了建造者设计模式。
- Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息。
- SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式。
- XmlConfigParser :负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory。
3. SqlSessionFactory涉及的设计模式(Build建造者设计模式)
3.1 什么是建造者设计模式
使用多个简单的对象一步一步构建一个复杂的对象,这种模式属于创建型模式,目前是创建型的最佳模式。
3.2 SqlSessionFactoryBuilder与SqlSessionFactory之间关系
- SqlSessionFactoryBuilder是Builder模式中建造者,负责SqlSessionFactory对象的创建以及
- SqlSessionFactroy对象内部所需要内容的组装.
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);
}
4. Configuration介绍
MyBatis介绍支持开发人员通过配置文件与其进行交流,在配置文件中配置所有信息,在框架运行时,会被XMLConfigBuilder解析并存储在一个configuration对象中,donfiguratioin对象会被作为参数传送给DeFaultSQLSessionFacFactory,DeFaultSQLSessionFacFactory根据configuration对象信息为client创建对应特征的SqlSession对象。
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
解释一下上面那段源码,可以看见XML文件中<configuration>中的所有内容都解析并放入到了XNode中剩下的只要调用XNode方法获取自己想要的内容即可。解析标签XPathParser的evalNode方法来解析为XNode的。XML解析可以熟悉一下Dom4j。