我的编程空间,编程开发者的网络收藏夹
学习永远不晚

一文搞懂 MyBatis的事务管理机制

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

一文搞懂 MyBatis的事务管理机制

一、事务概述

事务是指要么全部执行成功,要么全部回滚的一组操作。在数据库中,一般使用 ACID 规则来约束事务,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。在 MyBatis 中,也遵循了这一规则。

MyBatis中的事务是指一系列数据库操作,这些操作要么全部执行成功,要么全部执行失败。如果操作过程中发生错误,所有对数据库的修改都将被回滚,即还原到最初状态。事务是确保数据一致性和完整性的关键机制之一。

在MyBatis中,我们可以通过三种方式来管理事务:

  • 编程式管理事务:在代码中显式开启、提交或回滚事务。

  • 声明式管理事务:通过AOP代理实现事务管理,可以让代码更简洁,更容易维护。

  • 注解式管理事务:通过注解方式管理事务,是声明式管理事务的一种扩展方式。

以上三种方式,最常用的是声明式管理事务,它可以将事务管理和业务逻辑分离,降低代码的耦合度,提高代码的可读性和可维护性。在MyBatis中,声明式事务管理需要借助Spring框架来实现。

在使用声明式事务管理时,我们需要在Spring配置文件中配置TransactionManager和TransactionProxyFactoryBean两个bean,其中TransactionManager负责事务管理,TransactionProxyFactoryBean负责AOP代理。

下面是一个示例:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.example.UserMapper"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

<bean id="userMapperProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager" />
    <property name="target" ref="userMapper" />
    <property name="transactionAttributes">
        <props>
            <prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="insert*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="delete*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

在编写完上述配置后,我们就可以对UserMapper接口中的方法进行事务管理了。例如,在UserService类中,我们可以注入userMapperProxy,并调用其中的方法:

@Service
public class UserService {

    @Autowired
    UserMapper userMapperProxy;

    @Transactional
    public void addUser(User user) {
        userMapperProxy.addUser(user);
    }
}

在代码中,通过@Transactional注解声明了该方法需要进行事务管理,当方法执行过程中发生异常时,事务将会回滚。

MyBatis支持多种事务管理方式,但是建议使用声明式事务管理,因为它能够最大程度地降低代码的耦合度,并提高代码的可读性和可维护性。

二、MyBatis 实现事务的方式

MyBatis 实现事务也有多种方式,其中最常用的方式有两种:编程式事务和声明式事务。接下来我们将分别来介绍这两种方式。

1. 编程式事务

编程式事务就是通过编写代码来手动管理事务,主要包括以下几个步骤:

1)获取 SqlSession 对象;

2)设置自动提交为 false;

3)执行数据库操作;

4)提交事务;

5)关闭 SqlSession。

代码示例如下:

SqlSession sqlSession = sqlSessionFactory.openSession(false);
try {
    // 执行数据库操作
    sqlSession.insert("insertUser", user);
    sqlSession.update("updateUser", user);
    
    // 提交事务
    sqlSession.commit();
} catch (Exception e) {
    // 回滚事务
    sqlSession.rollback();
} finally {
    // 关闭 SqlSession
    sqlSession.close();
}

以上代码中,通过设置自动提交为 false 来关闭自动提交事务的方式,然后在 try 块中执行需要进行事务管理的数据库操作,如果出现异常则回滚事务,否则提交事务,并在 finally 中关闭 SqlSession。

2. 声明式事务

声明式事务就是在配置文件中通过事务管理器来管理事务,这种方式更加灵活和方便,我们只需要在配置文件中配置好即可。MyBatis 内置了两个事务管理器:JDBC 和 Spring。

(1)JDBC 事务管理器

JDBC 事务管理器是 MyBatis 内置的一个事务管理器,在 SqlSessionFactory 的配置文件中进行配置:

<transactionManager type="JDBC" />

(2)Spring 事务管理器

Spring 事务管理器是基于 Spring 框架的事务管理器,需要引入 Spring 的包,并在 MyBatis 的配置文件中配置:

<transactionManager type="SPRING" />

在使用 Spring 事务管理器时,还需要在 Spring 的配置文件中配置事务管理器和数据源,具体可以参考 Spring 的文档。

三、事务源码理解

(1)TransactionFactory

在 MyBatis 中,事务工厂需要实现 org.apache.ibatis.transaction.TransactionFactory 接口,该接口有一个方法:

Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

该方法用于创建一个新的 Transaction 实例。

例如,如果你要使用 JDBC 来管理事务,可以使用默认提供的 JdbcTransactionFactory 类来创建事务工厂。以下是一个创建事务工厂的示例代码:

import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;

public class MyTransactionFactory {
    public static TransactionFactory createTransactionFactory() {
        return new JdbcTransactionFactory();
    }
}

以上代码中,我们使用 JdbcTransactionFactory 创建一个新的事务工厂。实际上,在 MyBatis 的配置文件中,可以直接引用这个工厂。

例如:

<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>
  <!-- Mapper 配置 -->
</configuration>

以上代码中,我们使用了 <transactionManager type="JDBC"/> 来配置事务管理器的类型,并且在 <dataSource> 标签中指定了数据源的类型为 POOLED,也就是一个连接池数据源。

在实际应用中,还可以通过自定义事务工厂来创建其他类型的事务。例如,如果你要使用 Atomikos 来管理事务,可以自定义一个 AtomikosTransactionFactory 类来创建事务工厂。

(2)JdbcTransaction

在 MyBatis 中,Transaction 接口的默认实现是 JdbcTransaction 类。这个类的创建是在 JdbcTransactionFactory 工厂类中完成的。

以下是 JdbcTransactionFactory 工厂类中用于创建 Transaction 实例的代码:

@Override
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
  return new JdbcTransaction(dataSource, level, autoCommit);
}

在这段代码中,我们可以看到工厂方法 newTransaction() 的实现。该方法接收三个参数:数据源、事务隔离级别和是否自动提交。

newTransaction 方法中,我们使用这些参数创建一个新的 JdbcTransaction 实例,并将其返回。JdbcTransaction 类中实现了 Transaction 接口,因此可以直接返回。

以下是 JdbcTransaction 类的主要源码:

public class JdbcTransaction implements Transaction {

  protected Connection connection;
  protected DataSource dataSource;
  protected TransactionIsolationLevel level;
  protected boolean autoCommit;

  public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) throws SQLException {
    dataSource = ds;
    level = desiredLevel;
    autoCommit = desiredAutoCommit;
    openConnection();
    setDesiredAutoCommit();
    setDesiredTransactionIsolation();
  }

  // ...其他方法

}

JdbcTransaction 类中,我们创建了一个基本的事务对象,它包含了一些属性,例如事务管理器、连接、事务隔离级别等等。在构造函数中,我们使用传入的参数来初始化这些属性值。

除了构造函数之外,还有一些其他的方法用于对事务进行操作,例如提交、回滚、关闭等。这些方法都是从 Transaction 接口中继承来的。

因此,在 MyBatis 中,创建一个新的事务就是通过事务工厂和相应的创建方法来创建一个特定类型的事务对象。而在事务对象中,我们可以对事务进行各种操作。

(3)ManagedTransaction

在 MyBatis 中,除了 JdbcTransaction 之外,还提供了另外一种称为 ManagedTransaction 的事务实现,它是一种由容器或框架来管理的事务,而不是 MyBatis 内部来管理。

ManagedTransaction 接口的默认实现是 SpringManagedTransaction 类。该类实现了 MyBatis 的 Transaction 接口,但其本身并不处理任何事务逻辑,而是委托给 Spring 框架进行处理。

以下是 SpringManagedTransaction 类的主要源码:

public class SpringManagedTransaction implements Transaction {

  private final DataSource dataSource;
  private Connection connection;
  private boolean isConnectionTransactional;
  private boolean autoCommit;

  public SpringManagedTransaction(DataSource dataSource) {
    this.dataSource = dataSource;
  }

  @Override
  public Connection getConnection() throws SQLException {
    if (this.connection == null) {
      openConnection();
    }
    return this.connection;
  }

  // ...其他方法

}

SpringManagedTransaction 类中,我们使用传入的数据源来创建一个新的事务对象。在 getConnection() 方法中,如果当前连接不存在,则会打开一个新的连接并返回;否则直接返回已经存在的连接。

需要注意的是,SpringManagedTransaction 并不自行管理事务,而是将事务管理工作交给了 Spring 框架。因此,如果要使用 SpringManagedTransaction,我们需要在 Spring 配置文件中配置相应的事务管理器,例如 DataSourceTransactionManagerJpaTransactionManager 等。

总之,相比于 JdbcTransactionManagedTransaction 更适合在容器或框架中使用,而不是在 MyBatis 内部使用。如果你使用 Spring 或其他类似的框架来管理事务,则可以考虑使用 ManagedTransaction 来实现 MyBatis 的事务管理。

四、测试用例

接下来我们将通过一个示例来详细介绍 MyBatis 的事务管理机制。假设我们需要执行一个复杂的业务操作,需要同时更新多个表,我们就可以使用编程式事务来管理事务。

在 Mapper.xml 文件中,编写如下 SQL 语句:

<insert id="insertUser" parameterType="com.example.User">
    insert into user (id, name, age) values (#{id}, #{name}, #{age})
</insert>

<update id="updateAccount" parameterType="com.example.Account">
    update account set balance = #{balance} where id = #{id}
</update>

然后我们编写一个 Service 类来调用 Mapper 文件中的方法,代码如下:

public class UserService {
    private SqlSessionFactory sqlSessionFactory;

    public UserService(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    public void addUserAndAccount(User user, Account account) {
        SqlSession sqlSession = sqlSessionFactory.openSession(false);
        try {
            // 执行数据库操作
            sqlSession.insert("insertUser", user);
            sqlSession.update("updateAccount", account);
            
            // 提交事务
            sqlSession.commit();
        } catch (Exception e) {
            // 回滚事务
            sqlSession.rollback();
        } finally {
            // 关闭 SqlSession
            sqlSession.close();
        }
    }
}

以上代码中,我们通过 openSession(false) 来获取 SqlSession 对象,并设置自动提交为 false,然后在 try 块中执行数据库操作,如果出现异常则回滚事务,否则提交事务,并在 finally 中关闭 SqlSession。在实际开发中,我们可以将 SqlSession 放入 Spring 管理中,这样就更加方便了。

以上就是一文搞懂 MyBatis的事务管理机制的详细内容,更多关于MyBatis 事务管理的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

一文搞懂 MyBatis的事务管理机制

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文搞懂 MyBatis的事务管理机制

MyBatis是一款优秀的持久层框架,相信很多Java后端开发人员对它都不会陌生。本文将从事务概述、MyBatis实现事务的方式、事务实现源码分析方面详细解析MyBatis的事务管理机制,需要的朋友可以参考下
2023-05-20

一文带你读懂SpringBoot中的事务管理

一文带你读懂SpringBoot中的事务管理?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Springboot内部提供的事务管理器是根据autoconfigur
2023-05-31

PostgreSQL的事务管理机制是什么

PostgreSQL的事务管理机制是基于ACID(原子性、一致性、隔离性、持久性)特性的。它支持事务的原子性,即事务中的所有操作要么全部成功提交,要么全部失败回滚;一致性,即事务执行前后数据库的状态保持一致;隔离性,即多个事务之间应该是相互
PostgreSQL的事务管理机制是什么
2024-04-09

如何理解Spring的Hibernate事务管理机制

如何理解Spring的Hibernate事务管理机制,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。主要讲了Spring 声明式事务让我们从复杂的Hibernate事务处理中
2023-06-17

一文解析spring中事务的传播机制

今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。Spring中的事务Spring的事务其实就是数据库的事务操作,符合ACID标
2023-07-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录