Transaction manager for mybatis source code analysis

Previous: Configuration of mybatis source code analysis

It mainly analyzes the reading of configuration files in the process of building SqlSessionFactory.

This time we focus on analyzing the transaction manager of mybatis

Still starting from the example given by the official website, the configuration file 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>

 

There are two nodes, environments and mappers, under the root node configuration.

environments: environment, mybatis can configure multiple environments to apply SQL mapping to multiple databases. For example, development, testing, and production correspond to different databases.

mappers: mapper, providing the address of the mapping file.

The transactionManager under the environment is the object to be analyzed now.

There are two types of transaction managers in mybatis, JDBC and MANAGED.

JDBC: Direct use of JDBC's commit and rollback settings, which rely on the connection obtained from the data source to manage the scope of the transaction.

MANAGED: Instead of committing or rolling back a connection, let the container manage the entire lifecycle of the transaction.

Analyze the example, previously analyzed

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

 

Now let's analyze

SqlSession session = sqlSessionFactory.openSession();

openSession in DefaultSqlSessionFactory

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

 

Look at the relationship between the various classes

JdbcTransaction and ManagedTransaction correspond to the two types of transaction managers, JDBC and MANAGED.

Since ManagedTransaction does almost nothing, focus on analyzing JdbcTransaction.

Because JdbcTransaction uses JDBC's commit and rollback settings directly, it relies on the connection obtained from the data source to manage the scope of the transaction.

Then take a look directly at the JDBC transaction

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 isolation level

TRANSACTION_NONE: Transactions are not supported

TRANSACTION_READ_UNCOMMITTED: Dirty reads, non-repeatable reads and dummy reads are allowed.

TRANSACTION_READ_COMMITTED: Dirty reads are not allowed, non-repeatable reads and dummy reads are allowed.

TRANSACTION_REPEATABLE_READ: Dirty reads and non-repeatable reads are not allowed, virtual reads are allowed.

TRANSACTION_SERIALIZABLE: Dirty reads, non-repeatable reads and dummy reads are not allowed.

Dirty read: A transaction updates data, but the transaction has not yet committed, another transaction can get the update results that the transaction has not committed.

Non-repeatable read: The same transaction reads the same data multiple times during the entire transaction process, and the result of each read is different.

Virtual read: After the same query is executed multiple times in the entire transaction process, the result set obtained by the query is different. The virtual read is for multiple records.

Non-repeatable read: different column values; virtual read: different number of records.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325477379&siteId=291194637