- 三哥
内容来自【自学星球】
欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。
想要了解更多,欢迎访问👉:自学星球
--------------SSM系列源码文章及视频导航--------------
创作不易,望三连支持!
SSM源码解析视频
👉点我
Spring
SpringMVC
MyBatis
---------------------【End】--------------------
SqlSession是mybatis的核心接口之一,是myabtis接口层的主要组成部分,对外提供了mybatis常用的api。myabtis提供了两个SqlSesion接口的实现,常用的实现类是DefaultSqlSession,它相当于一个数据库连接对象,在一个SqlSession中可以执行多条SQL语句。
前面我们已经分析等到了 SqlSessionFactory ,下面我们再来看看通过它如何拿到 SqlSession 。
// 获得会话;
SqlSession session = sqlSessionFactory.openSession();
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()
public SqlSession openSession() {
// 第一个参数解释:configuration.getDefaultExecutorType(),获取了默认的执行器类型 SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource
/**
* ExecutorType 指定Executor的类型,分为三种:SIMPLE, REUSE, BATCH,默认使用的是SIMPLE
* TransactionIsolationLevel 指定事务隔离级别,使用null,则表示使用数据库默认的事务隔离界别
* autoCommit 是否自动提交,传过来的参数为false,表示不自动提交
*/
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,即执行器
// 它是真正用来Java和数据库交互操作的类,后面会展开说。
final Executor executor = configuration.newExecutor(tx, execType);
// 创建DefaultSqlSession对象返回,其实现了SqlSession接口
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();
}
}
上述方法主要分以下几个步骤:
我们先来看看常规的 environment 配置
//配置environment环境
<environments default="development">
<environment id="development">
/** 事务配置 type= JDBC、MANAGED
* 1.JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
* 2.MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。
*/
<transactionManager type="JDBC" />
/** 数据源类型:type = UNPOOLED、POOLED、JNDI
* 1.UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。
* 2.POOLED:这是JDBC连接对象的数据源连接池的实现。
* 3.JNDI:这个数据源的实现是为了使用如Spring或应用服务器这类的容器
*/
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xhm" />
<property name="username" value="root" />
<property name="password" value="root" />
//默认连接事务隔离级别
<property name="defaultTransactionIsolationLevel" value=""/>
dataSource>
environment>
environments>
environment 配置的解析在 2.1.5 节有分析。
再 environment 配置中 transactionManager type=“JDBC” 和 dataSource type=“POOLED” ,则生成的transactionManager 为 JdbcTransactionFactory,DataSourceFactory 为 PooledDataSourceFactory 。
回到 openSessionFromDataSource 方法,接着看看 getTransactionFactoryFromEnvironment 源码。
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#getTransactionFactoryFromEnvironment
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory#newTransaction(javax.sql.DataSource, org.apache.ibatis.session.TransactionIsolationLevel, boolean)
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
直接通过工厂方法创建了一个JdbcTransaction对象,并传参DataSource ,事务隔离级别null,自动提交false三个参数,我们来看看 JdbcTransaction 这个类。
public class JdbcTransaction implements Transaction {
//数据库连接对象
protected Connection connection;
//数据库DataSource
protected DataSource dataSource;
//数据库隔离级别
protected TransactionIsolationLevel level;
// MEMO: We are aware of the typo. See #941
//是否自动提交
protected boolean autoCommmit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
//设置dataSource和隔离级别,是否自动提交属性
//这里隔离级别传过来的是null,表示使用数据库默认隔离级别,自动提交为false,表示不自动提交
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
}
//提交功能是通过Connection去完成的
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
}
//回滚功能是通过Connection去完成的
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}
//关闭功能是通过Connection去完成的
@Override
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
}
//获取连接是通过dataSource来完成的
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
}
JdbcTransaction主要维护了一个默认autoCommit为false的Connection对象,对事物的提交,回滚,关闭等都是接见通过Connection完成的。
回到 openSessionFromDataSource 方法,看下面这行代码
// 创建Executor,即执行器
// 它是真正用来Java和数据库交互操作的类,后面会展开说。
final Executor executor = configuration.newExecutor(tx, execType);
org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)
//创建一个执行器,默认是SIMPLE
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//根据executorType来创建相应的执行器,Configuration默认是SIMPLE
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
//创建SimpleExecutor实例,并且包含Configuration和transaction属性
executor = new SimpleExecutor(this, transaction);
}
//如果要求缓存,生成另一种CachingExecutor,装饰者模式,默认都是返回CachingExecutor
/**
* 二级缓存开关配置示例
*
*
*
*/
// cacheEnabled 默认为 true
if (cacheEnabled) {
//CachingExecutor使用装饰器模式,将executor的功能添加上了二级缓存的功能,二级缓存会单独文章来讲
executor = new CachingExecutor(executor);
}
//此处调用插件,通过插件可以改变Executor行为,此处我们后面有机会在分析
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
executor 包含了 Configuration 和刚刚创建的 Transaction,默认的执行器为 SimpleExecutor,如果开启了二级缓存(默认开启一级缓存
),则 CachingExecutor 会包装 SimpleExecutor,然后依次调用拦截器的 plugin 方法返回一个被代理过的Executor对象。
executor 默认情况下就是 CachingExecutor ,只不过如果二级缓存没有开启,则实际还是调用 SimpleExecutor 去执行(CachingExecutor 包装了 SimpleExecutor 类型),后面会分析该类。
// 创建DefaultSqlSession对象返回,其实现了SqlSession接口
return new DefaultSqlSession(configuration, executor, autoCommit);
大致看一下 DefaultSqlSession 类
public class DefaultSqlSession implements SqlSession {
/**
* mybatis全局配置新
*/
private final Configuration configuration;
/**
* SQL执行器
*/
private final Executor executor;
/**
* 是否自动提交
*/
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
// ...
}
SqlSession的所有查询接口最后都归结位Exector的方法调用,后面在分析。
好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见
。
由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
感谢您的阅读,十分欢迎并感谢您的关注。