MyBatis 教程

MyBatis 配置 transactionManager 标签

在 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.
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号