spring声明式事务 @Transactional 不回滚的多种情况以及解决方案

下面我将详细讲解“spring声明式事务 @Transactional 不回滚的多种情况以及解决方案”。

一、@Transactional不回滚的多种情况

1.1 默认回滚规则

  • 默认情况下,Spring会对所有运行时异常进行回滚。也就是说,只有在方法中抛出RuntimeException及其子类异常时,才会导致事务回滚。
  • 对于受检异常(即继承自Exception的异常),Spring不会自动回滚。

1.2 编程式事务管理

  • 在使用编程式事务管理时,如果没有手动设置任何异常回滚,则不会触发回滚。
  • 如果手动设置回滚条件,但设置的异常类型不是运行时异常,则不会回滚。

1.3 同一个类中的方法调用

  • 由于@Transactional是基于AOP实现的,因此同一个类中的方法调用,不会触发事务回滚。原因是在一个事务方法内部调用另外一个有@Transactional注解的方法,Spring框架并不会再次开启一个新的事务,而是继续使用已经存在的事务。因此即使另一个方法抛出异常,也不会影响当前事务的提交或回滚。

1.4 异常被捕获的情况

  • 如果事务方法抛出一个异常,但是该异常在被当前方法所捕获,而没有被抛到事务方法之外,这时事务并不会进行回滚。这是由于Spring事务管理是通过AOP实现的,只有在方法执行时抛出异常,才会被AOP的拦截器捕获到,才能进行事务回滚。

1.5 事务回滚后的异常被捕获

  • 如果事务方法抛出一个异常导致事务回滚,但是该异常在后续代码中被捕获并处理了,而不是被抛出到上层调用方法,那么回滚不会被成功执行。在处理完异常后,后续代码会继续执行,而不是回滚到之前的状态。这时需要在异常处理中重新抛出异常,在上层调用方法中进行处理。

二、解决方案

2.1 修改默认回滚规则

  • 可以使用@Transactional注解的rollbackFor属性来指定异常回滚的类型,如@Transactional(rollbackFor = Exception.class),这样就可以把受检异常也包含进回滚的规则中,实现更加灵活的回滚控制。

2.2 手动开启新的事务

  • 可以在方法中调用自己所在的类的另一个有@Transactional注解的方法时,通过Propagation.REQUIRES_NEW参数来指定该方法必须开启新的事务,例如:

```java
@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private UserMapper userMapper;

  @Override
  @Transactional
  public void updateUser(User user) {
      userMapper.updateUser(user);
      // 更新用户信息后需要往用户日志表中插入一行新纪录
      this.insertUserLog(user);
  }

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void insertUserLog(User user) {
      UserLog userLog = new UserLog();
      userLog.setUserId(user.getUserId());
      userLog.setOperateType("update");
      userMapper.insertUserLog(userLog);
  }

}
```

2.3 解决异常被捕获的情况

  • 可以将捕获异常的代码改为抛出异常,或者通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()来手动设置回滚状态。例如:

java
@Override
@Transactional
public void updateUser(User user) {
try {
userMapper.updateUser(user);
throw new RuntimeException("test");
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw e;
}
}

2.4 解决事务回滚后的异常被捕获

  • 可以通过TransactionAspectSupport.currentTransactionStatus().hasRollbackOnly()方法来判断当前事务是否已经回滚,如果已经回滚,则需要重新抛出异常,例如:

java
@Override
@Transactional
public void updateUser(User user) {
try {
userMapper.updateUser(user);
throw new RuntimeException("test");
} catch (Exception e) {
if (TransactionAspectSupport.currentTransactionStatus().hasRollbackOnly()) {
throw e;
}
// ...处理异常
}
}

好了,这就是关于“spring声明式事务 @Transactional 不回滚的多种情况以及解决方案”的完整攻略。希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring声明式事务 @Transactional 不回滚的多种情况以及解决方案 - Python技术站

(0)
上一篇 2023年5月21日
下一篇 2023年5月21日

相关文章

  • MySQL数据库实验实现简单数据库应用系统设计

    MySQL数据库实验实现简单数据库应用系统设计攻略 1. 实验目的 通过设计和实现简单的数据库应用系统,掌握MySQL数据库的基本操作和应用。 2. 实验环境 操作系统:Windows/Linux/macOS 数据库:MySQL 3. 实验步骤 3.1 数据库设计和创建 根据需求设计数据库的表结构,并在MySQL中创建对应的数据库、表和数据。 示例:创建一个…

    database 2023年5月19日
    00
  • 问个高难度的复杂查询(在一个时间段内的间隔查询)

    需要先明确一下,“在一个时间段内的间隔查询”指的应该是查询某个时间段内的时间间隔数据。 在SQL中,我们可以利用时间函数和子查询来完成这个复杂查询。 首先我们需要明确两个时间点,一开始时间point_begin,和一个时间间隔interval,这两个变量可以从用户输入得到。 接下来就是SQL查询语句的构建: SELECT * FROM table_name …

    database 2023年5月21日
    00
  • centos7搭建redis主从复制,并模拟故障切换。

     Cntos7搭建redis主从复制,并模拟故障主从切换 主从复制搭建 主机:192.168.161.179 从机:192.168.161.180 1、        安装主redis 自己本地环境,关闭防火墙。  #sed -i ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/selinux/config #se…

    Redis 2023年4月12日
    00
  • 同一个sql语句 连接两个数据库服务器

    连接两个数据库服务器可以使用MySQL的Federated存储引擎。Federated存储引擎可以将远程MySQL服务器的数据表视为本地数据表,从而实现对多台数据库服务器的访问。 下面是连接两个数据库服务器的完整攻略: 1.创建Federated引擎表 首先,在本地MySQL服务器上创建一个Federated引擎表,该表将访问远程MySQL服务器上的数据表。…

    database 2023年5月21日
    00
  • go-cqhttp环境配置及安装过程

    下面是关于”go-cqhttp环境配置及安装过程”的完整攻略: 一、概述 go-cqhttp是一款基于Goland开发的跨平台QQ机器人框架,支持多种平台和协议,可通过HTTP API进行交互。本篇攻略将详细介绍go-cqhttp环境配置和安装的过程。 二、安装go-cqhttp 下载安装包 下载go-cqhttp安装包,可以在官方GitHub库中下载,也可…

    database 2023年5月22日
    00
  • Mysql 日期时间 DATE_FORMAT(date,format)

    当我们在使用 MySQL 数据库时,常常会遇到对日期时间进行格式化输出的需求。MySQL 提供了 DATE_FORMAT() 函数用来格式化日期时间值。 DATE_FORMAT() 函数接受两个参数:date和format。其中,date为日期时间值,可以是一个字符串,也可以是一个合法的日期时间类型的格式;format则为表示日期时间输出格式的字符串。 日期…

    database 2023年5月22日
    00
  • mysql临时表用法分析【查询结果可存在临时表中】

    让我们从头开始了解一下mysql临时表的用法和使用场景。 什么是临时表? 临时表是一种特殊的表,只在当前会话内存在,一旦会话关闭,临时表就会被自动删除。临时表的优点是:- 可以提高MySQL实例的并发处理能力;- 减轻锁竞争,提升查询效率;- 临时表可以存储查询结果,增加查询灵活性 临时表的创建 在MySQL中,创建临时表分为两种方式:- 使用CREATE …

    database 2023年5月22日
    00
  • mysql自增长id用完了该怎么办

    当MySQL数据表中的自增长ID达到上限,就需要考虑如何解决这个问题。下面是一些常见的解决方法: 方法一:修改自增长ID的起始值 查看数据表的当前自增长ID值 SHOW TABLE STATUS WHERE Name=’table_name’; 需要替换table_name为数据表的名称。 修改数据表的自增长ID起始值 ALTER TABLE table_n…

    database 2023年5月21日
    00
合作推广
合作推广
分享本页
返回顶部