Spring @Transactional事务失效的原因分析

yizhihongxing

让我们来详细讲解 Spring @Transactional事务失效的原因分析。事务是应用程序中非常重要的概念,对于保证数据一致性具有至关重要的作用。Spring框架提供了@Transactional注解作为声明式事务管理的方式,可以极大的减轻我们对事务的控制。然而,有时候我们会发现@Transactional失效了,这时候我们需要对其原因进行分析。

一. 什么是 @Transactional?

@Transactional是Spring框架的注解,用于声明式的事务管理。在使用@Transactional注解的方法中,Spring会为其生成一个动态代理,这个代理会在方法开始调用时开启一个事务,在方法执行结束后,根据方法的执行情况决定是提交事务,还是回滚事务。

二. @Transactional 失效的原因

在实际的应用场景中,我们很容易发现@Transactional注解失效了的情况。下面我们将逐个解释事务失效的原因。

1. 对于只有一个@Transactional的方法内部调用了其他带有事务注解的方法

示例1

@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void addUser(User user) {
        userDao.addUser(user);
        try {
            // 在当前方法内调用带有事务注解的方法
            // 由于事务的传播行为默认为REQUIRED,所以会继承当前的事务
            // 这个调用的方法执行了回滚操作,导致当前事务也回滚了
            addUserWithError(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional
    public void addUserWithError(User user) {
        userDao.addUser(user);
        throw new RuntimeException("模拟数据重复添加异常");
    }

}

如果这个时候调用UserService.addUser方法,在执行addUserWithError方法时发生了异常,则由于事务传播行为的默认设置为Required,当前事务也会回滚。在addUser方法结束以后,针对于User的事务逻辑并没有生效,数据没有被插入进去。

示例2

@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private RoleService roleService;

    @Override
    public void addUser(User user, Role role) {
        userDao.addUser(user);
        // 在当前方法内调用另一个 Service 方法
        // 默认情况下,这个 Service 方法会在当前事务内进行操作
        roleService.addRole(role);
    }

}

@Service
@Transactional
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleDao roleDao;

    @Override
    public void addRole(Role role) {
        roleDao.addRole(role);
    }

}

因为在调用addRole方法时,当前事务并没有被关闭,所以实际上数据并没有被提交。因此,如果发现在@Transactional注解声明的方法内部调用了另一个带有事务注解的方法,务必保证被调用的方法不会回滚事务。

2. 对于一个类中的方法相互调用

假如一个类中有多个方法,在其中一个方法中使用了@Transactional注解,而另一个方法却直接调用了该方法。这时候事务就会失效。这是因为在这个类中,Spring通过生成代理类来管理事务,因此在同一个类中的方法中的@Transactional注解不会被代理类所拦截,从而导致事务失效。

示例

@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    public void addUsers(List<User> users) {
        users.forEach(this::addUser);
    }

    public void addUser(User user) {
        userDao.addUser(user);
    }

}

如果在调用addUsers方法之前没有开启事务,则在addUser方法内插入数据库的数据并不会回滚。要解决这个问题,我们可以使用编程式事务的方式,在每个方法内部都手动开启和关闭事务。

三. 总结

在使用@Transactional注解时,务必要注意各个事务之间的传播行为。对于只有一个@Transactional的方法内部调用了其他带有事务注解的方法,务必保证被调用的方法不会回滚事务。对于一个类中的方法相互调用,需要注意事务的传播行为。如果遇到事务失效的问题,可以使用编程式事务的方式手动开启和关闭事务。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring @Transactional事务失效的原因分析 - Python技术站

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

相关文章

  • 新手必须知的Node.js 4个JavaScript基本概念

    我来为您讲解“新手必须知的Node.js 4个JavaScript基本概念”的攻略。 1. JavaScript中变量声明及数据类型 在JavaScript中,声明变量需要用到var关键字,变量名可以包含字母、数字、下划线等,但不能以数字开头。例如: var name = "Tom"; var age = 20; 在JavaScript中…

    database 2023年5月21日
    00
  • Table ‘xxx’ is marked as crashed and should be repaired 错误解决方法参考

    当MySQL表出现”Table ‘xxx’ is marked as crashed and should be repaired”错误时,表示数据库表已经崩溃或损坏。这时需要对于该表进行修复,以确保正常的数据查询和操作。 以下为解决该错误的步骤和示例说明: 步骤一:进入MySQL命令行 通过终端等方式进入MySQL命令行。在MySQL命令行中进行数据表的修…

    database 2023年5月18日
    00
  • docker中使用mongodb数据库详解(在局域网访问)

    下面是关于“docker中使用mongodb数据库详解(在局域网访问)”的完整攻略,包括步骤、示例及注意事项等。 步骤: 下载并安装Docker及Docker-compose Docker可以从官网https://www.docker.com/get-started下载对应系统的安装包进行安装。Docker-compose也同样可以从官网https://do…

    database 2023年5月22日
    00
  • Cassandra 和 MySQL 的区别

    Cassandra 和 MySQL 都是常见的数据库。虽然它们都可以存储和查询数据,但是它们在很多方面有很大的区别。下面就对它们的不同点逐一进行讲解。 1. 数据模型 Cassandra 和 MySQL 的数据模型是完全不同的。Cassandra 是一个列式数据库,每个列族(column family)包含了多个行(rows), 每个行由多个列组成。Cass…

    database 2023年3月27日
    00
  • SpringBoot数据库初始化datasource配置方式

    关于SpringBoot数据库初始化datasource配置方式的攻略,我将会给出以下的详细讲解: 1. 配置application.properties 在SpringBoot项目中,我们可以通过application.properties配置文件来设置初始化datasource。以下是一个基本的数据库配置,其中涵盖了必要的属性: spring.datas…

    database 2023年5月18日
    00
  • 数据库性能优化二:数据库表优化提升性能

    数据库性能优化二:数据库表优化提升性能 提高数据库性能的一个重要方面就是优化数据库表,因为数据库表是数据库的核心组成部分,它的设计和选择直接影响整个系统的性能。本文将介绍几种优化数据库表的技巧和策略,并且提供一些示例来帮助你更好地了解这些概念。 选择合适的数据类型 选择正确的数据类型是优化数据库表的最基本和最重要的一步。使用较小的数据类型可以节省磁盘空间,并…

    database 2023年5月19日
    00
  • 使用BAT批处理执行sql语句的代码

    使用BAT批处理执行SQL语句的过程可以分为以下几个步骤: 安装MySQL命令行工具批处理文件需要用到MySQL命令行工具,所以需要先安装MySQL数据库并配置好环境变量。 编写SQL语句在执行SQL语句之前,需要先编写好需要执行的SQL语句,并将其保存到文本文件中。 编写批处理脚本使用文本编辑器编写批处理脚本文件,例如“run_sql.bat”,可以参考以…

    database 2023年5月21日
    00
  • MySQL导出所有Index和约束的方法

    MySQL是一个常用的关系型数据库管理系统。在实际的开发中,为了避免数据的重复、不一致等问题,我们会定义Index和约束。但有时我们需要将这些Index和约束导出到其他数据库中,这时我们就需要导出这些Index和约束的定义。 下面是MySQL导出所有Index和约束的方法: 1. 使用SHOW CREATE TABLE命令 使用SHOW CREATE TAB…

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