在 MyBatis 中有两种事务管理器类型,也就是 type="[JDBC|MANAGED]":
JDBC – 这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期(比如 Spring 或 JEE 应用服务器的上下文)。默认情况下它会关闭连接。然而一些容器并不希望这样,因此如果你需要从连接中停止它,将 closeConnection 属性设置为 false。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
这两种事务管理器都不需要任何属性。
其实,JDBC 类型对应 JdbcTransactionFactory、JdbcTransaction;MANAGED 类型对应 ManagedTransactionFactory、ManagedTransaction。它们分别实现了 TransactionFactory 和 Transaction 接口。如下图:


你要自定义事务管理器需要实现 TransactionFactory 和 Transaction 接口。
(1)TransactionFactory 接口源码如下:
public interface TransactionFactory {
  /**
   * Sets transaction factory custom properties.
   * @param props
   */
  void setProperties(Properties props);
  /**
   * Creates a {@link Transaction} out of an existing connection.
   * @param conn Existing database connection
   * @return Transaction
   * @since 3.1.0
   */
  Transaction newTransaction(Connection conn);
  
  /**
   * Creates a {@link Transaction} out of a datasource.
   * @param dataSource DataSource to take the connection from
   * @param level Desired isolation level
   * @param autoCommit Desired autocommit
   * @return Transaction
   * @since 3.1.0
   */
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}该接口定义了三个方法,一个用来设置属性,另外两个用来创建事务对象。
(2)Transaction 接口源码如下:
public interface Transaction {
  /**
   * Retrieve inner database connection
   * @return DataBase connection
   * @throws SQLException
   */
  Connection getConnection() throws SQLException;
  /**
   * Commit inner database connection.
   * @throws SQLException
   */
  void commit() throws SQLException;
  /**
   * Rollback inner database connection.
   * @throws SQLException
   */
  void rollback() throws SQLException;
  /**
   * Close inner database connection.
   * @throws SQLException
   */
  void close() throws SQLException;
}该接口定义了四个方法,分别用于获取数据库连接、提交事务、回滚事务、关闭数据库连接。
当我们实现了上面两个接口,需要在别名中进行声明,例如:
<typeAliases> <!-- 声明自定义的事务管理器 --> <typeAlias alias="my_transaction" type="com.hxstrive.mybatis.transaction.demo1.MyTransactionFactory" /> </typeAliases>
然后在 <transactionManager> 标签的 type 属性中指定定义事务管理器别名,如:my_transaction
<transactionManager type="my_transaction" />
我们配置类型别名,MyBatis 是怎样发现我们自定义的事务管理器的呢?查看源码就可以知道了,如下图:

进入 resolveClass 方法,该方法将调用 resolveAlias 方法去解析别名(这里别名为 my_transaction),如下:

resolveAlias 方法中将从 TYPE_ALIASES Map中根据 key 获取别名对应的类全限定名称。如下:

(1)MyBatis 配置文件 mybatis-cfg.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>
    <properties resource="database.properties"/>
    <typeAliases>
        <!-- 声明自定义的事务管理器 -->
        <typeAlias alias="my_transaction" type="com.hxstrive.mybatis.transaction.demo1.MyTransactionFactory" />
    </typeAliases>
    <environments default="MySqlDatabase" >
        <environment id="MySqlDatabase" >
            <!-- 使用自定义事务管理器 -->
            <transactionManager type="my_transaction" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/hxstrive/mybatis/transaction/demo1/UserMapper.xml" />
    </mappers>
</configuration>(2)自定义事务工厂类,代码如下:
package com.hxstrive.mybatis.transaction.demo1;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class MyTransactionFactory implements TransactionFactory {
    private static final String NAME = MyTransactionFactory.class.getSimpleName();
    @Override
    public void setProperties(Properties props) {
        System.out.println(NAME + " setProperties()");
    }
    @Override
    public Transaction newTransaction(Connection conn) {
        System.out.println(NAME + " newTransaction()");
        return new MyTransaction(conn);
    }
    @Override
    public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
        System.out.println(NAME + " newTransaction()");
        try {
            return new MyTransaction(dataSource.getConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}(3)自定义事务类,代码如下:
package com.hxstrive.mybatis.transaction.demo1;
import org.apache.ibatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
public class MyTransaction implements Transaction {
    private static final String NAME = MyTransaction.class.getSimpleName();
    private Connection connection;
    public MyTransaction(Connection connection) {
        this.connection = connection;
    }
    @Override
    public Connection getConnection() throws SQLException {
        System.out.println(NAME + " getConnection()");
        return this.connection;
    }
    @Override
    public void commit() throws SQLException {
        System.out.println(NAME + " commit()");
        if(null != this.connection && !this.connection.getAutoCommit()) {
            this.connection.commit();
        }
    }
    @Override
    public void rollback() throws SQLException {
        System.out.println(NAME + " rollback()");
        if(null != this.connection && !this.connection.getAutoCommit()) {
            this.connection.rollback();
        }
    }
    @Override
    public void close() throws SQLException {
        System.out.println(NAME + " close()");
        if(null != this.connection) {
            this.connection.close();
        }
    }
}(3)定义 Mapper 接口和配置文件
a、UserMapper.java
package com.hxstrive.mybatis.transaction.demo1;
public interface UserMapper {
    /** 查询用户数 */
    int getUserCount();
}b、UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.hxstrive.mybatis.transaction.demo1.UserMapper"> <!-- 查询用户数 --> <select id="getUserCount" resultType="integer"> select count(*) from `user` </select> </mapper>
(4)客户端代码如下:
package com.hxstrive.mybatis.transaction.demo1;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public class TransactionDemo {
    public static void main(String[] args) throws Exception {
        String cfgName = "com/hxstrive/mybatis/transaction/demo1/mybatis-cfg.xml";
        InputStream input = Resources.getResourceAsStream(cfgName);
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlFactory = factoryBuilder.build(input);
        SqlSession sqlSession = sqlFactory.openSession(true);
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        int userCount = userMapper.getUserCount();
        System.out.println("用户总数=" + userCount);
        sqlSession.close();
    }
}运行客户端代码,输出结果如下:
MyTransactionFactory setProperties() 2020-09-13 15:59:08,269 DEBUG [org.apache.ibatis.logging.LogFactory] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2020-09-13 15:59:08,316 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 2020-09-13 15:59:08,317 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 2020-09-13 15:59:08,317 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. 2020-09-13 15:59:08,317 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections. MyTransactionFactory newTransaction() 2020-09-13 15:59:08,934 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Created connection 1555690610. MyTransaction getConnection() 2020-09-13 15:59:08,971 DEBUG [com.hxstrive.mybatis.transaction.demo1.UserMapper.getUserCount] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@5cb9f472] 2020-09-13 15:59:08,972 DEBUG [com.hxstrive.mybatis.transaction.demo1.UserMapper.getUserCount] - ==> Preparing: select count(*) from `user` 2020-09-13 15:59:09,080 DEBUG [com.hxstrive.mybatis.transaction.demo1.UserMapper.getUserCount] - ==> Parameters: 2020-09-13 15:59:09,138 DEBUG [com.hxstrive.mybatis.transaction.demo1.UserMapper.getUserCount] - <== Total: 1 用户总数=3 MyTransaction close() 2020-09-13 15:59:09,139 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Returned connection 1555690610 to pool.
