mybatis之SqlSessionFactory主要分析了SqlSessionFactory的构建过程.
mybatis源码分析之Configuration主要分析了构建SqlSessionFactory的过程中配置文件的读取.
这次重点分析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(); } }
看一下各个类之间的关系
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:不允许脏读、不可重复的读和虚读.
脏读:一个事务对数据进行更新,但事务还没有提交,另一个事务就可以取到该事务没有提交的更新结果。
不可重复读:同一个事务在整个事务过程中对同一笔数据进行多次读取,每次读取结果都不同。
虚读:同一个查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。虚读针对的是多条记录。
不可重复读:列值的不同; 虚读:记录数量的不同。