SqlSessionFactory的作用
Mybatis代码在一开始的使用首先就是进行xml文件的解析, 把所有配置都要存入Configuration对象中, SqlSessionFactory的作用就是创建SqlSession , SqlSession 就是一个接口, 定义了调用Statemment 和传入参数 调用sql语句, 所以sqlsession是可以当作sql执行的一个对象。
在创建出SeqSessionFactory对象之后,我们会调用openSession进行SqlSession对象创建。
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);// 默认的执行器, 默认的隔离级别,不自动提交
}
所以具体构建SeqSession对象的方法是在:
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();/*错误信息重置*/
}
}
创建执行器:
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);//设置插件, executor进行动态代理
return executor;
}
从上面可以看出如果开启了二级缓存, 执行器是会被一个缓存执行器进行装饰, 还有一个点就是插件扩展的第一个接口, Executor执行器。如果指定了插件就会代理指向器。
为什么SqlSessionFactory是线下安全而SqlSession不是线程安全的?
如果看过Mybatis官网的,就会发现官网一开始介绍SqlSessionFactory和SqlSession就说了,SqlSessionFactory只用创建一个该对象,当作全局来使用, 而SqlSession 不能作为全局对象, 只能当前线程使用。
从对SqlSessionFactory的创建代码看出, sqlSessionFactory持有了 configuration对象, 并且SqlSessionFacotry创建SqlSession的过程中, 并没有对这个Configuration全局对象进行修改,所以SqlSessionFactory并不存在线程安全问题。推进整个项目就使用一个SqlSessionFactory,而SqlSession本来就存在线程安全问题,因为他在指向过程中创建对象, 赋值一系列操作, 如果多个线程去指向SqlSession就会出现资源的竞争。
其中一个比较明显的点, 在应为二级缓存是和MapperStatement绑定的, 所以多个SqlSession 或者 多个线程去指向 就会导致共同去修改缓存, 这必然会存在线程不安全问题,所以Mybatis肯定做过一些处理。。