本文共 7152 字,大约阅读时间需要 23 分钟。
mybaits源码分析(三) 事务管理
前言:在mybaits源码分析(一) 核心执行流程事务这一块几乎是没讲到过。本篇主要讲解mybaits事务管理的实现机制,介绍mybaits事务设计接口和不同的实现,以及不同的事务实现JdbcTransaction 和 ManagedTransaction的具体实现不同,并且对mybaits配置文件解析,创建事务对象和实际使用的流程进行了分析。
一、概述:
对数据库的事务而言,应该具有以下几点:创建(create)、提交(commit)、回滚(rollback)、关闭(close)。对应地,MyBatis将事务抽象成了Transaction接口,其接口定义如下:public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; }
MyBatis的事务管理分为两种形式:
1) 使用JDBC事务管理(JdbcTransaction),即用java.sql.Connection完成事务的创建、提交、回滚、关闭。 2) 使用MANAGED事务管理(ManagedTransaction),这种机制MyBatis自身不会去实现事务管理,由提供数据源或链接的外层框架或容器实现。二、事务相关类
1、主要类介绍
Transaction : 事务接口 TransactionFactory : 负责创建事务的工厂接口 JdbcTransactionFactory : 负责创建jdbc事务的工厂 JdbcTransaction:Jdbc事务实现 ManagedTransactionFactory:负责创建Managed事务的工厂 ManagedTransaction:Managed事务的实现2、类图
3、JdbcTransaction的实现
JdbcTransaction直接使用JDB的提交和回滚事务管理机制,它依赖于从dataSource中取得链接connection,connection对象获取被延迟到调用getConnection,如果autocommit设置为on,那么它会忽略commit和rollback。
直观的讲,就是JdbcTransaction是使用java.sql.Connection的commit和rollback,JdbcTransaction相当于对java.sql.Connection的事务处理进行了一次包装,Transaction事务管理都是通过java.sql.Connection实现。public class JdbcTransaction implements Transaction { private static final Log log = LogFactory.getLog(JdbcTransaction.class); protected Connection connection; protected DataSource dataSource; protected TransactionIsolationLevel level; protected boolean autoCommmit; public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) { dataSource = ds; level = desiredLevel; autoCommmit = desiredAutoCommit; } public JdbcTransaction(Connection connection) { this.connection = connection; } public Connection getConnection() throws SQLException { if (connection == null) { openConnection(); } return connection; } public void commit() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Committing JDBC Connection [" + connection + "]"); } connection.commit(); } } public void rollback() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Rolling back JDBC Connection [" + connection + "]"); } connection.rollback(); } } public void close() throws SQLException { if (connection != null) { resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } connection.close(); } } // ..... 省略 }
4、ManagedTransaction实现
ManagedTransaction让容器来管理事务Transaction的整个生命周期,意思就是说,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权利移交给了容器来实现。
public class ManagedTransaction implements Transaction { private static final Log log = LogFactory.getLog(ManagedTransaction.class); private DataSource dataSource; private TransactionIsolationLevel level; private Connection connection; private boolean closeConnection; public ManagedTransaction(Connection connection, boolean closeConnection) { this.connection = connection; this.closeConnection = closeConnection; } public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) { this.dataSource = ds; this.level = level; this.closeConnection = closeConnection; } public Connection getConnection() throws SQLException { if (this.connection == null) { openConnection(); } return this.connection; } public void commit() throws SQLException { // Does nothing } public void rollback() throws SQLException { // Does nothing } public void close() throws SQLException { if (this.closeConnection && this.connection != null) { if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + this.connection + "]"); } this.connection.close(); } }
三、事务相关配置加载
1、配置文件
下面指定了一个mybaits的数据源的xml配置案例
2、我们从解析environments节点查看过程
Mybaits根据配置文件指定的事务管理器的类型字符串type(JDBC or MANAGED),来决定创建不同的事务工厂类, 并且把创建的事务工厂TransactionFactory和数据源包装到Environment对象中。
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); // 默认的id } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { // 当前环境的配置 // 事务工厂 : 具体是根据transactionManager的type属性指定。 TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); // 数据源工厂 DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory).dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } } } }
一个Configuration中只会创建一个Environment对象,一个Environment对象保存一个TransactionFactory和数据源。
四、事务对象的使用
上面讲了,我们解析配置,讲事务工厂类TransactionFactory和数据源包装到了Environment对象中,而Environment对象 是全局Configuration的一个属性,下面我们看看事务相关类的使用。
1、事务对象在那个时候创建?
我们知道创建一个SqlSession的时候,会对应的创建一个Executor,而Executor是我们实际执行增删改查的类,那么事务就是创建SqlSession的时候,包装到Executor内。我们直接看SqlSessionFactory的openSession的调用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); // 组装executor和configuration到DefaultSqlSession 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(); } }
2、事务何时开启?如何提交回滚?
如果我们需要开启事务,那么需要设置在创建SqlSession的使用,调用 SqlSessionFactory.openSession(flase), 底层调用的是JDBC的
connection.setAutoCommit(desiredAutoCommit) 如果事务提交或回滚,我们调用SqlSessionFactory.close(),实际调用的是executor的close,然后executor会调用Trancation的close。范例代码: SqlSession sqlSession = SqlSessionFactory.openSession(false); sqlSession.update('statementId',param); sqlSession.selectOne('queryStatementID',param); sqlSession.commit(); sqlSession.close();
转载地址:http://cruni.baihongyu.com/