赞
踩
SqlSession 是使用 MyBatis 的主要 Java 接口,我们可以通过它来执行一些命令,获取映射器示例和管理事务,所以可以将SqlSession看成是管理mybatis的一次会话,不过它也确实是会话的意思,一次api请求维护一个SqlSession。
//将配置文件通过io流的方式打开
InputStream inputStream= Resources.getResourceAsStream("org/apache/ibatis/test/MyBatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = build.openSession();
User user = sqlSession.selectOne("org.apache.ibatis.test.UserMapper.selectById", 1);
这是一个最简单的sqlSession获取方法,在 SqlSessionFactoryBuilder.build()方法中,已经将mybatis的所有文件全部都解析完成了,那么接下来就是通过工程去获取session,也就是 build.openSession();
工厂方法去获取session有几个步骤:
SqlSessionFactory 工厂默认是有两个的,一个是 DefaultSqlSessionFactory, 另一个是 SqlSessionManager,SqlSessionManage官方没有多做介绍,所以不多做说明,它主要就是通过代理管理sqlSession,实现多数据库的sqlSession的一个统筹。一般我们使用的主要是默认的DefaultSqlSessionFactory。
事务工厂默认是也是两个,一个是JdbcTransactionFactory,一个是
ManagedTransactionFactory,
由工厂实例化出来的事务也是两个,他们其实都是相互对应的。
在DefaultSqlSessionFactory类的 openSessionFromDataSource() 方法中,是opensession()的主要逻辑,它会获取环境然后根据配置实例化事务工厂,然后生产事务类,然后再根据策略去生成 Executor 执行器,默认是 SimpleExecutor(),最后返回DefaultSqlSession
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); // 根据策略生成Executor执行器 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(); } }
getTransactionFactoryFromEnvironment()方法可以看到,是从 environment 中拿的事务工厂,如果我们在配置环境时没有多加这一行,那么这里返回的就是ManagedTransactionFactory()工厂。
<transactionManager type="JDBC"></transactionManager>
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
两个事务工厂的 newTransaction()方法其实都是简单的 ,他们只是各自实例化了一下各自的事务,将数据源传入进去。至于事务最重要的openConnection()获取连接的方法,是在execute执行的时候才会触发,这里只是实例化。
--------------------- JdbcTransactionFactory ---------------------
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
--------------------- ManagedTransactionFactory---------------------
@Override
public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
}
实例化 execute的方法其实就是根据策略去分别实例化不同类型的执行器,然后将事务给弄进去,这里有个稍微需要注意的地方是,如果允许开启缓存,则会通过CachingExecutor去将executor代理掉来增加缓存层,cacheEnabled默认是true,也就是缓存是开启的。
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); } // 如果允许缓存,会通过 CachingExecutor 去代理一层,怎还缓存层 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 拦截器插件 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
最后就是拦截器插件的拦截了。如果有插件的话,则会通过pluginAll去代理一下,插件之所以可以拦截的实现就是在这里,它最终会调用Plugin 的wrap方法去代理,而Plugin 上有个我们非常熟悉的标志,InvocationHandler ,没错,就是动态代理,拦截器插件的原理就是通过动态代理来实现的。
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public class Plugin implements InvocationHandler {
一切都处理完成之后,就是将构造好的 sqlsession返回去就好了,openSession()虽然有个open,但其实只是构建了一下sqlsession,连接并未获取。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。