事务注解@Transactional又失效了!

简介: @Transactional失效场景

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来保证线程安全的,事务和当前线程绑定。

相关文章
|
7月前
|
XML Java 关系型数据库
@Transactional注解的失效场景
@Transactional注解的失效场景
119 1
|
7月前
|
Java 编译器 数据库
@Transactional中指定rollbackFor,弊端以及不能回滚的时候
@Transactional中指定rollbackFor,弊端以及不能回滚的时候
250 3
|
7月前
|
Java 编译器 数据库
在事务注解@Transactional中指定rollbackFor
在事务注解@Transactional中指定rollbackFor
63 0
|
23天前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
2月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
39 2
|
2月前
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
71 0
|
7月前
|
Java 编译器 Spring
@transactional注解失效情况
@transactional注解失效情况
|
7月前
|
Java 数据库 Spring
@Transactional 失效场景介绍
【2月更文挑战第5天】
645 1
@Transactional 失效场景介绍
|
Java 数据库 Spring
@Transactional 注解失效问题
@Transactional 注解失效问题
112 0
|
缓存 Java 数据库连接
Spring源码剖析之Transactional事务
我们知道使用@Transactional,要满足以下条件 1、配置数据源 DataSource 2、配置事务管理器 PlatformTransactionManager 3、配置类上标识 @EnableTransactionManagement
190 0

热门文章

最新文章