导读
上一篇文章介绍了Mybatis是怎样读取并解析mybatis-config.xml和xxxMapper.xml等xml信息并封装到Configuration对象中。这一篇文章主要介绍Mybatis的主要对象SqlSession和事务是怎样管理和执行的。带着两个疑问:1. 构造好的Configuration对象是在哪里用的?2. SqlSession又是怎样创建的?
一、使用Configuration对象:
回到XMLConfigBuilder的parse方法中,这个方法调用了一个主要方法parseConfiguration()解析完xml配置文件之后,返回一个configuration对象,如下
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
// 主要方法,解析xml标签等配置信息放到configuration中
this.parseConfiguration(this.parser.evalNode("/configuration"));
//返回configuration对象
return this.configuration;
}
}
build(parser.parse());
这个build方法就是传入一个Configuration对象,然后构建一个DefaultSqlSession对象。
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
到些SqlSession对象就构建出来了
配置文件解析流程
获取到SqlSessionFactory之后 ,就可以创建SqlSession了。
二、构建SqlSession:
从前面的配置文件解析流程我们知道,得到的sqlSessionFactory是DefaultSqlSessionFactory类型
sqlSession = sqlSessionFactory.openSession();
所以上面调用的openSession()方法为DefaultSqlSessionFactory中的方法。
public class DefaultSqlSessionFactory implements SqlSessionFactory {
//配置文件所有内容
private final Configuration configuration;
//创建session
@Override
public SqlSession openSession() {
//调用的是另外一个openSessionFromDataSource方法
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
//其实是调用这个方法
//protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//对应xml标签 ,这个在配置文件解析的时候就已经存放到configuration中了。
final Environment environment = configuration.getEnvironment();
//构建事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//构建一个事务对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//创建一个executor来执行SQL
final Executor executor = configuration.newExecutor(tx, execType);
//创建一个DefaultSqlSession对象并返回
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
创建事务Transation:
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
TransactionFactory有两个子类,如下:
事务工厂类型可以配置为JDBC类型或者MANAGED类型。
- JdbcTransactionFactory生产JdbcTransaction。
- ManagedTransactionFactory生产ManagedTransaction。
如果我们配置的是MANAGED,会把事务交给容器来管理,比如JBOSS,Tomcat。因为我们是本地跑的程序,如果配置成MANAGED就会不有任何事务。
但是,如果是Spring+Mybatis,则没有必要配置,因为我们会直接在applicationContext.xml里配置数据源和事务管理器,从而覆盖Mybatis的配置。
三、创建Executor
// 把事务传给newExecutor()方法创建执行器Executor对象。
configuration.newExecutor(tx, execType)
// 调用configuration的newExecutor方法创建Executor。
final Executor executor = configuration.newExecutor(tx, execType);
//Configuration中
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;
}
创建Excutor的过程分为三步:
第一步:创建执行器
Executor的基本类型有三种:SIMPLE为默认类型。
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}
Mybatis Excutor类图:
提问:为什么要让抽象类BaseExecutor实现Executor接口,然后让具体实现类继承抽象类呢?
这就是模板方法模式的实现。
模板方法模式就是定义一个算法骨架,并允许子类为一个或者多个步骤提供实现。模板方法是得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤。
抽象方法是在子类汇总实现的,每种执行器自己实现自己的逻辑,BaseExecutor最终会调用到具体的子类。
抽象方法:
protected abstract int doUpdate(MappedStatement var1, Object var2) throws SQLException;
protected abstract List doFlushStatements(boolean var1) throws SQLException;
protected abstract List doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;
protected abstract Cursor doQueryCursor(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4) throws SQLException;
第二步:缓存装饰
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
如果cacheEnabled=true,会用装饰器设计模式对Executor进行装饰。
第三步:插件代理
executor = (Executor) interceptorChain.pluginAll(executor);
到此,执行器创建的就搞定了。
Executor创建完毕后,就该创建DefaultSqlSession了,如下:
//创建一个DefaultSqlSession对象并返回
return new DefaultSqlSession(configuration, executor, autoCommit);
进入DefaultSqlSession的构造方法:
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
}
DefaultSqlSession中包含两个重要属性:configuration和executor
- configuration 存放配置信息
- executor 执行器
到此,SqlSession对象构建完毕。
sqlSession = sqlSessionFactory.openSession();
// 这里的sqlSession其实就是DefaultSqlSession:
// sqlSession = new DefaultSqlSession();
构建SqlSession过程如下图:
参照文档: mybatis官网-配置、腾讯云博客