事务注解@Transactional又失效了

文章详细介绍了Spring中@Transactional注解的事务传播属性,如REQUIRED、NOT_SUPPORTED、REQUIRES_NEW等,以及不同的事务隔离级别,如READ_UNCOMMITTED、READ_COMMITTED等。同时,讨论了事务管理中可能出现的失效情况,包括未被Spring管理、方法不能被重写、内部调用、异常处理不当、rollbackFor使用错误以及数据库引擎不支持事务。最后提到了多线程环境下事务的处理问题。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1、相关基本知识

1.1事务的传播方式

//如果有事务, 那么加入事务, 没有的话新建一个(默认)
@Transactional(propagation=Propagation.REQUIRED)
//容器不为这个方法开启事务 
@Transactional(propagation=Propagation.NOT_SUPPORTED)
//不管是否存在事务, 都创建一个新的事务, 原来的挂起, 新的执行完毕, 继续执行老的事务 
@Transactional(propagation=Propagation.REQUIRES_NEW) 
//必须在一个已有的事务中执行, 否则抛出异常
@Transactional(propagation=Propagation.MANDATORY) 
//必须在一个没有的事务中执行, 否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NEVER) 
//如果其他bean调用这个方法, 在其他bean中声明事务, 那就用事务, 如果其他bean没有声明事务, 那就不用事务
@Transactional(propagation=Propagation.SUPPORTS) 

1.2事务的隔离级别

// 读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
// 读取已提交数据(会出现不可重复读和幻读) Oracle默认
@Transactional(isolation = Isolation.READ_COMMITTED)
// 可重复读(会出现幻读) MySQL默认
@Transactional(isolation = Isolation.REPEATABLE_READ)
// 串行化
@Transactional(isolation = Isolation.SERIALIZABLE)

ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.

ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

1.3其他属性

在这里插入图片描述

  • timeout 事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
  • readOnly 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
  • rollbackFor 用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
  • noRollbackFor 抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

2、事务失效场景

2.1未被Spring管理

事务方法所在类并没有被Spring管理,则Spring事务会失效。这种对于Springboot项目其实不会的,你把@Service注释掉,Controller中注入UserService是会报错的。
在这里插入图片描述

2.2方法不能被重写

这里的意思是带@Transactional注释的方法必须是可重写的,那我们知道private、static、final修饰的方法均不能被重写。
在这里插入图片描述

2.3同一个类中方法相互调用

这里我们在同一个类中方法A调用了方法B,在方法B上使用@Transactional,此时方法B中出现异常,我们是希望他能回滚的。
在这里插入图片描述
可惜并没有回滚事务
在这里插入图片描述
声明式事务实现原理是面向切面编程,通过cglib创建代理proxy,当我们访问带 @Transactional方法,如果通过spring容器获取bean,实际访问的是代理对象,代理对象已经在带 @Transactional方法前后增加了事务相关的逻辑。而当调用带 @Transactional方法的调用方是同类方法时,调用的是this对象的方法,没有通过spring容器获取bean,就无法访问到代理对象,事务也就没有生效。

我们把@Transactional注解放到方法A上就可以了。此时即便方法B是private修饰的也无所谓

在这里插入图片描述

2.4异常被catch了

基于2.3的例子,假如把方法B中的异常catch了却没有抛出异常,事务也是不会回滚的。
在这里插入图片描述
解决办法:通常我们会在Springboot项目中自定义一个异常,在catch语句块中抛出自定义异常即可。

2.5rollbackFor使用不当

rollbackFor默认值为UncheckedException,包括了RuntimeException和Error。

在使用@Transactional注解时不指定rollbackFor,Exception及其子类都不会触发回滚。
在这里插入图片描述
继承自Runtime Exception或 Error 的是非检查型异常,而继承自 Exception 的则是检查型异常。

2.6数据库引擎不支持事务

比如MySQL数据库选用MyISAM存储引擎,而MyISAM存储引擎本身不支持事务,事务肯定不会生效。

2.7多线程问题

如果你去面试,面试官问你多线程事务如何回滚,你要是回答用@Transactional注解,就可以直接回去了。Spring的事务是通过ThreadLocal来保证线程安全的,事务和当前线程绑定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注解@Transactional失效时,可能有几个原因: 1. 事务管理器配置错误:首先,确保你已经正确配置了事务管理器。在Spring中,事务管理器负责管理数据库事务。你可以使用JDBC事务管理器、Hibernate事务管理器或JTA事务管理器等。请确保你选择的事务管理器与你的项目结构和配置相匹配。 2. 注解扫描问题:注解@Transactional需要Spring容器来扫描并解析它。如果你的注解被忽略或没有正确扫描到,它就会失效。请确保在你的配置文件(如applicationContext.xml)中进行了正确的注解扫描。 3. 方法调用问题:注解@Transactional应该应用在方法上,而不是类上。请确保你将该注解正确地应用在需要进行事务管理的方法上。 4. 异常处理问题:当一个带有注解@Transactional的方法发生异常时,Spring会根据异常类型来判断是否要回滚事务。如果你没有适当地处理异常或使用了不正确的异常处理机制,事务可能会失效。请确保你适当地处理了异常,并且使用了正确的异常处理机制。 5. 启用事务注解支持:在Spring中,你需要启用事务注解支持才能使@Transactional注解生效。你可以通过在配置文件中添加以下内容来启用支持: ```xml <tx:annotation-driven/> ``` 这将启用事务注解支持,并确保@Transactional注解生效。 如果你仍然遇到问题,可以提供更多的详细信息,以便能够更好地帮助你解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值