您的位置:首页 > 数据库

mybatis源码分析3 - sqlSession的创建

2018-01-09 12:03 591 查看

1 引言和主要类

初始化mybatis,也就是创建完单例SqlSessionFactory后,就进入到了mybatis的运行阶段。mybatis每次的运行都是通过SqlSession对象来进行,它是运行时的核心。不同于SqlSessionFactory,SqlSession不是线程安全的,故一般建议放在局部作用域中定义, 且使用完后close掉。我们使用mybatis创建SqlSession十分简单,代码如下

// 读入xml配置文件
String resource = "main/resources/SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactory,初始化mybatis的关键所在,上一节分析过了
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 利用SqlSessionFactory来创建SqlSession,这一节重点分析
SqlSession session = sessionFactory.openSession();


创建SqlSession十分简单,调用SqlSessionFactory的openSession()方法即可。但这个方法背后其实相当复杂,mybatis为我们做了很多幕后工作。我们先介绍下openSession()过程中要用到的主要类。

DefaultSqlSessionFactory:SqlSessionFactory的默认实现类,上一节我们讲到过。

Transaction:数据库事务,有JdbcTransaction和ManagedTransaction两个实现

Executor:调度器,sqlSession的select update等方法的真正实现,mybatis运行的核心。

DefaultSqlSession:sqlSession的默认实现类,其方法几乎均由Executor代理实现。

2 流程分析

我们从DefaultSqlSessionFactory这个默认工厂类的openSession()方法说起。

// SqlSessionFactory单例创建并开启一个sqlSession实例。sqlSession线程不安全,一般存放在局部作用域中,用完close即可。
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

// 开启sqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获取configuration的environment,它代表了运行的数据库环境,
// 由配置文件中的environments节点的environment子节点生成,创建SqlSessionFactory时指定其id,默认为default
final Environment environment = configuration.getEnvironment();

// environment实例中取出transactionFactory成员变量,然后实例化它。
// JdbcTransactionFactory创建JdbcTransaction,使用JDBC代理管理commit等事务
// ManagedTransactionFactory创建ManagedTransaction,自身不对事务进行处理,完全交给容器,如Spring
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

// 由事务transaction创建调度器Executor,SqlSession的几乎所有方法都是通过代理模式由Executor真正实现
// Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称SqlSession四大组件
// ExecutorType在XML配置文件的settings节点中设置(defaultExecutorType), 可以取SIMPLE REUSE BATCH,默认为SIMPLE
// SIMPLE表示简易执行器,REUSE为一种执行器重用预处理语句,BATCH则为批量专用的执行器。
final Executor executor = configuration.newExecutor(tx, execType);

// 构造SqlSession实例,mybatis默认的实现类为DefaultSqlSession
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();
}
}


mybatis先由初始化阶段创建在configuration中的environment变量来创建数据库事务,然后根据XML配置文件的settings节点中设置的defaultExecutorType来创建调度器Executor,最后就可以创建得到DefaultSqlSession实例了。下面我们来分析事务的创建

2.1 数据库事务Transaction的创建

Transaction有两个实现类,即JdbcTransaction和ManagedTransaction,他们分别由JdbcTransactionFactory和ManagedTransactionFactory工厂类来创建实例。JdbcTransaction本地事务由数据库本身来管理事务,其getConnection()从DataSource中得到, commit() rollback() close() 则由java.sql.Connection实例代理实现。

ManagedTransaction由容器来管理事务,其getConnection()从DataSource中得到,commit() rollback()均为空实现,不做任何事情,完全托管给容器。

下面以JDBCTransaction为例来看Transaction事务的创建

// 工厂类来创建事务实例
// @Param DataSource: 数据库源
// @Param level: 事务隔离级别,定义并发事务的处理方式。如A读时,B在写。
// @param autoCommit: 是否自动提交
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}


2.2 调度器Executor的创建

Executor是SqlSession的核心,其select update commit rollback close等方法均由Executor代理实现。Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称mybatis运行时四大组件。四大组件均可由用户通过插件注入,也都有默认实现。下面看创建Executor的源码

// 创建sqlsession执行器Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// executorType通过settings节点中的defaultExecutorType来设置,没有设置则默认为SIMPLE
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;

// 根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor
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);
}

// 如果打开了缓存,使用CachingExecutor包装下之前创建的executor,简单理解就是为executor添加了cache功能
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}

// 将执行器executor设置到plugins节点中设置的所有插件中,作为插件的目标执行器。
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}

public Object pluginAll(Object target) {
// 遍历所有插件,将传入的target,作为插件的目标执行器。插件通过配置XML文件的plugins节点设置。
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}


Executor根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor三个实现类,他们的基类为BaseExecutor。下一节我们分析selectList方法时,以SimpleExecutor这个默认的调度器为例分析。

2.3 SqlSession实例的创建

SqlSession的默认实现为DefaultSqlSession,其创建十分简单,构造方法如下

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}


其中executor成员最为关键,DefaultSqlSession的大部分方法均是通过它来代理实现。比如select update方法。而delete和insert方法均调用update方法来实现。

// select方法通过executor实现,典型的代理模式
// selectOne selectList均调用它实现
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
// 利用调度器Executor代理实现
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

// update方法通过executor实现,典型的代理模式
// insert update等DML操作均调用它实现
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 利用调度器Executor代理实现
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

public int insert(String statement, Object parameter) {
return update(statement, parameter);
}

public int delete(String statement, Object parameter) {
return update(statement, parameter);
}


3 总结

构建SqlSession的核心是创建调度器Executor,它是mybatis运行的核心。通过调度StatementHandler ParameterHandler ResultSetHandler来完成各种操作。四者合称SqlSession四大组件。后面一节我们以sqlSession.selectOne()方法为例来分析mybatis的CRUD操作的背后原理。

相关文章

mybatis源码分析1 - 框架

mybatis源码分析2 - SqlSessionFactory的创建

mybatis源码分析3 - sqlSession的创建

mybatis源码分析4 - sqlSession读写数据库完全解析

mybatis源码分析5 - mapper读写数据库完全解析

mybatis源码分析6 - mybatis-spring容器初始化

mybatis源码分析7 - mybatis-spring读写数据库全过程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息