详解MyBatis的SqlSession获取流程
作者:半夏之沫
前言
已知在MyBatis的使用中,使用MyBatis时会先读取配置文件mybatis-config.xml为字符流或者字节流,然后通过SqlSessionFactoryBuilder基于配置文件的字符流或字节流来构建SqlSessionFactory,然后再通过SqlSessionFactory的openSession() 方法获取SqlSession,示例代码如下所示。
public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(Resources.getResourceAsStream(resource)); SqlSession sqlSession = sqlSessionFactory.openSession(); }
上述示例代码中的SqlSessionFactory实际为DefaultSqlSessionFactory,本篇文章将对DefaultSqlSessionFactory获取SqlSession的流程进行学习。
正文
DefaultSqlSessionFactory的openSession() 方法如下所示。
public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
继续看openSessionFromDataSource() 方法的实现,如下所示。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // Environment中包含有事务工厂和数据源 final Environment environment = configuration.getEnvironment(); // 获取事务工厂 // 如果配置了JDBC事务,则获取JDBC事务工厂,否则获取MANAGED事务工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 创建事务 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建执行器 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(); } }
openSessionFromDataSource() 方法会先从Configuration中将Environment获取出来,Environment中包含有事务工厂和数据源,Environment是在MyBatis配置文件中进行配置并会在加载MyBatis配置文件时被添加到Configuration中。
MyBatis的配置文件中可以配置两种事务工厂,为JDBC事务工厂和MANAGED事务工厂,它们分别可以创建JDBC事务和MANAGED事务,类图如下所示。
获取事务工厂的getTransactionFactoryFromEnvironment() 方法如下所示。
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) { if (environment == null || environment.getTransactionFactory() == null) { // 配置了事务工厂则使用配置的事务工厂 // MyBatis可以配置JDBC和MANAGED这两种事务工厂 return new ManagedTransactionFactory(); } // 没做配置的情况下使用MANAGED事务工厂 return environment.getTransactionFactory(); }
MyBatis中如果使用JDBC事务,则事务的管理由java.sql.Connection完成,如果使用MANAGED事务,则MyBatis会将事务的管理交由WEB容器(Tomcat,JBoss等)来完成。以commit() 和rollback() 方法为例,看下JdbcTransaction和ManagedTransaction对这两个方法的实现,如下所示。
public class JdbcTransaction implements Transaction { // ...... @Override public void commit() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Committing JDBC Connection [" + connection + "]"); } connection.commit(); } } @Override public void rollback() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Rolling back JDBC Connection [" + connection + "]"); } connection.rollback(); } } // ...... } public class ManagedTransaction implements Transaction { // ...... @Override public void commit() throws SQLException { // 不做任何事情 } @Override public void rollback() throws SQLException { // 不做任何事情 } // ...... }
回到openSessionFromDataSource() 方法,创建好事务后,会构建执行器Executor,看一下newExecutor(Transaction transaction, ExecutorType executorType) 方法的实现,如下所示。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; // 根据ExecutorType的枚举值创建对应类型的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); } // 如果MyBatis配置文件中开启了二级缓存 if (cacheEnabled) { // 创建CachingExecutor作为Executor的装饰器,为Executor增加二级缓存功能 executor = new CachingExecutor(executor); } // 将插件逻辑添加到Executor中 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
在上面构建执行器Executor的方法中,主要是做了三件事情,解释如下。
第一件事情
,根据ExecutorType的枚举值创建对应类型的Executor,ExecutorType枚举值如下所示。
public enum ExecutorType { SIMPLE, REUSE, BATCH }
MyBatis提供了三种类型的Executor,分别为BatchExecutor,ReuseExecutor和SimpleExecutor,类图如下所示。
在BaseExecutor中定义了四个抽象方法,如下所示。
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException;
BaseExecutor提供的方法中会调用这四个抽象方法,同时这四个抽象方法需要由BatchExecutor,ReuseExecutor和SimpleExecutor根据各自的功能进行实现,所以Executor的设计使用了模板设计模式。
第二件事情
,如果在MyBatis配置文件中开启了二级缓存,则为Executor创建装饰器CachingExecutor,以增加对二级缓存功能的支持。CachingExecutor与Executor的关系如下所示。
CachingExecutor实现了Executor接口,同时CachingExecutor持有Executor的引用,这是装饰器模式的应用。关于MyBatis中的缓存,会在后续的文章中进行介绍。
第三件事情
,如果配置了插件,则将插件的逻辑添加到Executor中。关于MyBatis中的插件,会在后续的文章中进行介绍。
回到openSessionFromDataSource() 方法,创建好Executor后,就会调用DefaultSqlSession的构造方法创建一个DefaultSqlSession并返回,在DefaultSqlSession的构造方法中只是进行了简单的赋值,如下所示。
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; }
至此,SqlSession就创建出来了。
总结
SqlSession的获取是通过SqlSessionFactory的openSession() 方法,SqlSession的创建过程主要先是创建事务管理器,然后基于事务管理器创建执行器Executor,最后基于Executor创建SqlSession。
通常,SqlSessionFactory为DefaultSqlSessionFactory,创建出来的SqlSession为DefaultSqlSession。
整体的一个流程图如下所示。
以上就是详解MyBatis的SqlSession获取流程的详细内容,更多关于MyBatis SqlSession获取流程的资料请关注脚本之家其它相关文章!