《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《数据库实体设计合集》

摘要: 原创出处 https://my.oschina.net/u/657390/blog/663080 「udbwcso」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

这次重点分析mybatis的事务管理器

仍旧从官网给的例子着手分析,配置文件mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>

在根结点configuration下有environments和mappers两个结点.

environments:环境,mybatis可以配置多个环境即可以将 SQL 映射应用于多种数据库之中.如开发,测试,生产对应不同的数据库.

mappers:映射器,提供映射文件的地址.

在environment下的transactionManager就是现在要重点分析的对象.

mybatis中有两种类型的事务管理器,JDBC和MANAGED.

JDBC:直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。

MANAGED:不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。

对例子进行分析,之前分析过

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

现在再来分析

SqlSession session = sqlSessionFactory.openSession();

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 {
//根据配置获取环境
final Environment environment = configuration.getEnvironment();
//构建事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//通过事务工厂创建事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
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();
}
}

看一下各个类之间的关系

img

JdbcTransaction和ManagedTransaction对应事务管理器的两种类型JDBC和MANAGED.

由于ManagedTransaction几乎没做什么,所以重点分析JdbcTransaction.

因为JdbcTransaction直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。

那么直接来看看JDBC的事务

java.sql.Connection

/**
* A constant indicating that transactions are not supported.
*/
int TRANSACTION_NONE = 0;

/**
* A constant indicating that
* dirty reads, non-repeatable reads and phantom reads can occur.
* This level allows a row changed by one transaction to be read
* by another transaction before any changes in that row have been
* committed (a "dirty read"). If any of the changes are rolled back,
* the second transaction will have retrieved an invalid row.
*/
int TRANSACTION_READ_UNCOMMITTED = 1;

/**
* A constant indicating that
* dirty reads are prevented; non-repeatable reads and phantom
* reads can occur. This level only prohibits a transaction
* from reading a row with uncommitted changes in it.
*/
int TRANSACTION_READ_COMMITTED = 2;

/**
* A constant indicating that
* dirty reads and non-repeatable reads are prevented; phantom
* reads can occur. This level prohibits a transaction from
* reading a row with uncommitted changes in it, and it also
* prohibits the situation where one transaction reads a row,
* a second transaction alters the row, and the first transaction
* rereads the row, getting different values the second time
* (a "non-repeatable read").
*/
int TRANSACTION_REPEATABLE_READ = 4;

/**
* A constant indicating that
* dirty reads, non-repeatable reads and phantom reads are prevented.
* This level includes the prohibitions in
* <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the
* situation where one transaction reads all rows that satisfy
* a <code>WHERE</code> condition, a second transaction inserts a row that
* satisfies that <code>WHERE</code> condition, and the first transaction
* rereads for the same condition, retrieving the additional
* "phantom" row in the second read.
*/
int TRANSACTION_SERIALIZABLE = 8;

事务隔离级别

TRANSACTION_NONE:不支持事务

TRANSACTION_READ_UNCOMMITTED:允许脏读、不可重复的读和虚读.

TRANSACTION_READ_COMMITTED:不允许脏读,允许不可重复的读和虚读.

TRANSACTION_REPEATABLE_READ:不允许脏读和不可重复的读,允许虚读.

TRANSACTION_SERIALIZABLE:不允许脏读、不可重复的读和虚读.

脏读:一个事务对数据进行更新,但事务还没有提交,另一个事务就可以取到该事务没有提交的更新结果。

不可重复读:同一个事务在整个事务过程中对同一笔数据进行多次读取,每次读取结果都不同。

虚读:同一个查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。虚读针对的是多条记录。

不可重复读:列值的不同; 虚读:记录数量的不同。

666. 彩蛋

如果你对 MyBatis 感兴趣,欢迎加入我的知识一起交流。

知识星球

文章目录
  1. 1. 666. 彩蛋