2024-12-18  阅读(86)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1968749546

回答

在 Spring 中,目前最主流的管理事务的方式有两种,编程式事务和声明式事务。

编程式事务

编程式事务需要我们开发者手动编写代码来控制事务的开启、提交和回滚。我们可以利用 TransactionTemplate 或者 PlatformTransactionManager 来实现:

  • TransactionTemplate 是 Spring 提供的一种事务管理模板类,它封装了事务的开始、提交和回滚逻辑,我们只需要在模板中编写具体的业务代码就可以了。
  • PlatformTransactionManager 是 Spring 事务管理的核心接口,我们可以直接使用它来手动管理事务的生命周期。

编程式事务的优点在于它控制的事务粒度非常精细,我们可以非常灵活地控制事务的范围、传播行为、回滚逻辑。缺点就是增加了代码的复杂度,同时事务的管理和业务代码也耦合了。所以,它比较适用于那些需要灵活控制事务边界的场景。

声明式事务

声明式事务是目前 Spring 推荐的主流方式,它通过配置或者注解的方式将事务管理和业务代码解耦。目前 Spring 支持两种声明式事务:

  • 基于 @Transactional 注解

使用范围最广泛的事务管理方式。Spring 采用 AOP 的方式拦截带有 @Transactional 的方法,自动处理事务的开启、提交和回滚。

  • 基于 XML 配置

基于 XML 的已经逐渐被取代了,因为它比较适用于对事务规则有统一配置需求的场景,同时,XML 的配置非常冗余和繁琐。

详解

关于 声明式事务,大明哥就不过多介绍了,详细情况请阅读下面的面试题:

编程式事务详解

Spring 提供了两种实现方式:

  • 使用 TransactionTemplate
  • 使用 PlatformTransactionManager

使用 TransactionTemplate

TransactionTemplate 是 Spring 提供的一种模板方法模式的实现,它封装了事务的开始、提交和回滚逻辑。使用方只需要关注具体的业务逻辑,而不必关心底层的事务管理细节。如下:

@Service
public class SkUserService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void performTransaction() {
        transactionTemplate.execute(status -> {
            try {
                // 执行业务逻辑
                // 如果操作成功,没有抛出异常,事务会提交
            } catch (Exception e) {
                // 操作失败,事务回滚
                status.setRollbackOnly();
                throw e;
            }
        });
    }
}

TransactionTemplate 采用了一种比较优化的方式来简化事务的管理,它将事务管理的逻辑封装在模板中,避免了底层事务的繁琐操作,我们无需直接操作事务管理器,这样就会是的代码更加简洁。

我们直接看 execute()

  public <T> T execute(TransactionCallback<T> action) throws TransactionException {
    Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

    if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
      return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
    }
    else {
      TransactionStatus status = this.transactionManager.getTransaction(this);
      T result;
      try {
        result = action.doInTransaction(status);
      }
      catch (RuntimeException | Error ex) {
        // Transactional code threw application exception -> rollback
        rollbackOnException(status, ex);
        throw ex;
      }
      catch (Throwable ex) {
        // Transactional code threw unexpected exception -> rollback
        rollbackOnException(status, ex);
        throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
      }
      this.transactionManager.commit(status);
      return result;
    }
  }

从这里可以看出 TransactionTemplate 底层是基于 PlatformTransactionManager 事务管理器的,只不过它封装了一层而已。

使用 PlatformTransactionManager

PlatformTransactionManager 是 Spring 中管理事务的核心接口,负责协调事务的开启、提交和回滚。它是 Spring 事务管理体系的基石,提供了统一的事务管理抽象,能够适配多种事务资源(如 JDBC、JPA、Hibernate 等)。

使用它也比较简单,只需要在需要提交事务的时候获取 TransactionStatus 对象,执行业务逻辑后,调用 commit() 提交事务,如果出现异常,则调用 rollback() 回滚事务就可以了。如下:

@Service
public class SkService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void performTransaction() {
        TransactionDefinition definition = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            // 开始事务性操作
            System.out.println("开始执行事务逻辑");

            // 业务逻辑...

            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滚事务
            transactionManager.rollback(status);
            throw e;
        }
    }
}

PlatformTransactionManager 是 Spring 事务管理器接口,它有多个具体实现类,适配不同的数据访问技术。

  • DataSourceTransactionManager:基于 JDBC 的事务管理
  • JpaTransactionManager:基于 JPA 的事务管理
  • HibernateTransactionManager:基于 Hibernate 的事务管理
  • ChainedTransactionManager:多个事务管理器联合使用(如多数据源事务)

在上面代码中,我们看到了三个核心方法:

  • getTransaction():该方法用于开启一个新的事物,或者根据传播行为加入到已有的事务中。方法接受 TransactionDefinition 对象,返回 TransactionStatus 对象。
  • commit():提交事务。
  • rollback():回滚事务。

在上面代码中,我们也看到了两个比较重要的对象:TransactionDefinition 和 TransactionStatus。

TransactionDefinition

TransactionDefinition 是Spring 事务管理中定义事务属性的接口。它的作用是描述事务的基本属性,这些属性会影响事务的运行方式。具体包括:

  • 传播行为(Propagation): 定义 Spring 中事务的传播。设置方法如下:
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

关于 Spring 事务的传播行为,请阅读面试题:说一下 Spring 事务的传播机制

  • 隔离级别(Isolation): 决定事务间的并发控制级别。

隔离级别决定了事务间共享数据时的隔离程度,主要目的是防止并发问题(脏读、不可重复读、幻读)。设置方法如下:

definition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
  • 超时时间(Timeout): 限制事务的最大执行时间。

超时时间指事务的最大执行时间(以秒为单位)。如果事务执行时间超过设置值,则事务会被回滚。默认值为TIMEOUT_DEFAULT,即为 -1,表示没有超时限制。

这个参数主要是用于防止事务占用资源过长时间。设置方法:

definition.setTimeout(30); // 设置超时时间为 30 秒
  • 是否只读(Read-only): 指定事务是否只读,优化性能。

只读事务的属性用于优化事务的性能,适用于仅进行查询操作的事务。数据库在只读模式下,可以跳过一些不必要的事务管理工作(如加锁)。

definition.setReadOnly(true)
  • 事务名称(可选): 标识事务的唯一名称(仅在特定实现中可用)。

支持为事务指定名称,用于标识事务,方便调试和追踪。

definition.setName("skjavaTransaction");

TransactionStatus

TransactionStatus 也是 Spring 事务管理器中的一个核心接口,表示当前事务的状态信息,其主要作用是管理事务的状态并提供对事务的一些控制方法,包括:

  • 标记事务回滚:通过 setRollbackOnly() 方法,显式标记当前事务需要回滚。
  • 判断事务状态:提供方法查询事务是否为新事务、是否已完成等。
  • 支持保存点管理:对嵌套事务操作提供保存点支持。

在编程式事务 TransactionStatus 与事务管理器配合使用,可以实现对事务逻辑的精细化控制。典型的使用场景有。

  • 手动管理事务提交和回滚
@Service
public class SkService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void performTransaction() {
        TransactionDefinition definition = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            // 模拟业务逻辑异常
            if (someBusinessCondition()) {
                status.setRollbackOnly(); // 标记回滚
            }

            if (!status.isRollbackOnly()) {
                transactionManager.commit(status); // 提交事务
            } else {
                transactionManager.rollback(status); // 回滚事务
            }
        } catch (Exception e) {
            transactionManager.rollback(status); // 遇到异常回滚事务
            throw e;
        }
    }

    private boolean someBusinessCondition() {
        return true; // 模拟条件
    }
}
  • 嵌套事务的保存点管理

在一些复杂的业务场景中,我们可能需要对事务进行部分回滚操作,这个时候就可以使用保存点功能。

@Service
public class NestedTransactionService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void performNestedTransaction() {
        TransactionDefinition definition = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            // 第一个操作
            System.out.println("执行第一步事务逻辑");

            // 创建保存点
            Object savepoint = status.createSavepoint();

            try {
                // 第二个操作
                System.out.println("执行第二步事务逻辑");
                // 模拟异常
                throw new RuntimeException("模拟业务异常");
            } catch (Exception e) {
                // 回滚到保存点
                status.rollbackToSavepoint(savepoint);
                System.out.println("已回滚到保存点");
            }

            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

最后,关于 PlatformTransactionManager 相关源码,大明哥看了比较简单,这里就不多阐述了!


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文