Mybaits source code analysis (three) transaction management

Mybaits source code analysis (three) transaction management

Preface : In the mybaits source code analysis (1), the core execution process transaction is almost never mentioned. This article mainly explains the implementation mechanism of mybaits transaction management, introduces the mybaits transaction design interface and different implementations, and the specific implementation of different transaction implementations JdbcTransaction and ManagedTransaction are different, and analyzes the mybaits configuration file, creates transaction objects, and actually uses the process了Analysis.

1. Overview:
        
       For database transactions, it should have the following points: create (create), commit (commit), rollback (rollback), and close (close). Correspondingly, MyBatis abstracts the transaction into the Transaction interface, which is defined as follows:

    public interface Transaction {
        
          Connection getConnection() throws SQLException;
        
          void commit() throws SQLException;
        
          void rollback() throws SQLException;
        
          void close() throws SQLException;
        
        }

 The transaction management of MyBatis is divided into two forms:
       1) Use JDBC transaction management (JdbcTransaction), that is, use java.sql.Connection to complete the creation, submission, rollback, and closure of transactions.
       2) Using MANAGED transaction management (ManagedTransaction), this mechanism MyBatis does not implement transaction management by itself, but is implemented by an outer framework or container that provides data sources or links.

Two, transaction-related categories

1. Introduction to the main classes
            Transaction: Transaction interface
            TransactionFactory: factory interface responsible for creating transactions
            JdbcTransactionFactory: factory responsible for creating jdbc transactions
            JdbcTransaction: Jdbc transaction implementation
            ManagedTransactionFactory: factory responsible for creating managed transactions
            ManagedTransaction: implementation of managed transactions

2. Class diagram

3. Implementation of JdbcTransaction

       JdbcTransaction directly uses JDB's commit and rollback transaction management mechanism. It relies on obtaining the connection connection from the dataSource. The obtaining of the connection object is delayed until getConnection is called. If autocommit is set to on, then it will ignore commit and rollback.
        Intuitively speaking, JdbcTransaction uses the commit and rollback of java.sql.Connection. JdbcTransaction is equivalent to a package for the transaction processing of java.sql.Connection. Transaction management is implemented through 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. Implementation of ManagedTransaction

    ManagedTransaction allows the container to manage the entire life cycle of the transaction, which means that the use of ManagedTransaction's commit and rollback functions will not have any impact on the transaction, it will do nothing, it will transfer the power of transaction management to the container. achieve.

	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();
		    }
		  }	

  Three, transaction-related configuration loading

  1. Configuration file

下面指定了一个mybaits的数据源的xml配置案例
	  <environments default="development">
		<environment id="development">
			<!-- 事务:JDBC(简单jdbc的模式)或MANAGED-(不管理-比如交给spring)-->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源,采用mybatis连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="${db.driver}" />
				<property name="url" value="${db.url}" />
				<property name="username" value="${db.username}" />
				<property name="password" value="${db.password}" />
			</dataSource>
		</environment>
	 </environments>

 2. We view the process from the parsing environment node

Mybaits decides to create different transaction factory classes according to the type string type (JDBC or MANAGED) of the transaction manager specified in the configuration file, and packs the created transaction factory TransactionFactory and data source into the Environment object.

	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());
					}
				}
			}
		}

Only one Environment object is created in a Configuration, and one Environment object holds a TransactionFactory and data source.

Fourth, the use of transaction objects

As mentioned above, we analyze the configuration and talk about the transaction factory class TransactionFactory and data source packaged in the Environment object, and the Environment object is an attribute of the global Configuration, let's look at the use of transaction-related classes.

1. When was the transaction object created? 
         We know that when a SqlSession is created, an Executor will be created correspondingly, and Executor is the class that we actually perform addition, deletion, modification, and check. Then the transaction is packaged in the Executor when the SqlSession is created. We directly look at the call openSessionFromDataSource of SqlSessionFactory's openSession.

 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. When will the transaction start? How to submit a rollback?

          If we need to open the transaction, then we need to set the use of creating SqlSession, call SqlSessionFactory.openSession(flase), the bottom call is JDBC
    connection.setAutoCommit(desiredAutoCommit) If the transaction is committed or rolled back, we call SqlSessionFactory.close(), The actual call is the close of the executor, and then the close of the Trancation is called by the executor.

 范例代码:
	   SqlSession sqlSession = SqlSessionFactory.openSession(false);
	   sqlSession.update('statementId',param);
	   sqlSession.selectOne('queryStatementID',param);
	   sqlSession.commit();
	   sqlSession.close();
	 

 

 

 

Guess you like

Origin blog.csdn.net/shuixiou1/article/details/113574004