Spring声明式事务原理及事务失效场景?

Spring声明式事务原理

Spring声明式事务是基于AOP(面向切面编程)实现的。其核心流程如下:

1.事务管理器配置:

在Spring中,首先需要配置事务管理器,例如DataSourceTransactionManager(针对基于JDBC数据源的事务管理) 。它负责管理事务的开始、提交、回滚等操作,是事务管理的核心组件。

2.AOP切面织入:

Spring通过AOP机制,在方法调用前后织入事务相关逻辑。当一个标注了事务注解(如@Transactional)的方法被调用时,Spring会创建一个代理对象(基于JDK动态代理或CGLIB代理,取决于目标类是否实现接口 )。这个代理对象会在实际方法调用之前,调用事务管理器的begin()方法来开启事务;在方法正常执行结束后,调用事务管理器的commit()方法提交事务;如果方法执行过程中抛出异常,调用事务管理器的rollback()方法回滚事务。

3.传播行为与隔离级别处理:

@Transactional注解中可以指定事务传播行为(如REQUIRED、REQUIRES_NEW等)和隔离级别(如READ_COMMITTED、SERIALIZABLE等)。事务管理器会根据这些配置来正确处理事务之间的关系以及并发访问时的数据一致性问题。

事务失效场景

1.方法非public:@Transactional注解只能应用在public修饰的方法上。如果标注在private、protected或默认访问修饰符的方法上,事务不会生效。这是因为Spring的AOP代理机制在处理事务时,是基于Java的访问控制规则,非public方法无法被代理增强。

2.自调用问题:当一个类中的方法A调用同一类中的另一个被@Transactional标注的方法B时,事务不会生效。这是因为在这种情况下,没有经过代理对象调用,而是直接在目标对象内部调用,跳过了AOP的事务增强逻辑。例如:

typescript 复制代码
    @Service
    public class UserService {
        @Transactional
        public void methodA() {
            methodB();
        }
        @Transactional
        public void methodB() {
            // 业务逻辑
        }
    }

这里methodB的事务不会生效。

3. 未被Spring容器管理:如果一个类没有被Spring容器管理(没有使用@Component、@Service等注解将其纳入Spring容器),即使方法上标注了@Transactional,事务也不会生效,因为不存在Spring创建的代理对象来织入事务逻辑。

4. 异常被捕获处理:如果在被@Transactional标注的方法内部捕获了异常,并且没有重新抛出,事务不会回滚。例如:

typescript 复制代码
    @Service
    public class OrderService {
        @Transactional
        public void createOrder() {
            try {
                // 可能抛出异常的业务逻辑
                // 假设这里执行数据库插入操作出错
            } catch (Exception e) {
                // 捕获异常但未重新抛出
                e.printStackTrace();
            }
        }
    }

此时事务不会回滚,数据库操作会提交。

5.用的是mysql的MYISAM,这个引擎本身不支持事务。

6.rollbackFor没有设置对,比如默认没有任何配置,则方法内抛出IOException则不会回滚,需要配置@Transactional(rollbackFor=Exception.class)

7.@Transactional应用在final和static方法上,因为aop 默认是cglib代理(apringboot2.X开始),无法对final方法子类化。static是静态方法,属于类,不属于实例对象,无法被代理。

8.propagation传播机制配置错误。因为配置了Propagation.REQUIRES_NEW,是新启一个事务.因此2个事务之间是无法保证数据的一致性的。

java 复制代码
    public class OrderService {
    
        @Transactional(propagation=Propagation.REQUIRES_NEW)
            public void addOrderAndUser(int id) {
                try {
                    userMapper.addUser(id);
                    orderMapper.addOrder(id);
                    // 可能抛出异常的业务逻辑
                    // 假设这里执行数据库插入操作出错
                } catch (Exception e) {
                    // 捕获异常但未重新抛出
                    e.printStackTrace();
                }
            }
        @Transactional(propagation=Propagation.REQUIRES_NEW)
        public void addOrder(int id) {
            try {
                orderMapper.save(id);
                // 可能抛出异常的业务逻辑
                // 假设这里执行数据库插入操作出错
            } catch (Exception e) {
                // 捕获异常但未重新抛出
                e.printStackTrace();
            }
        }
    }
相关推荐
Funcy14 小时前
XxlJob 源码08:任务执行流程(三)之执行器揭秘
后端
AAA修煤气灶刘哥14 小时前
监控摄像头?不,我们管这个叫优雅的埋点艺术!
java·后端·spring cloud
2301_7720935614 小时前
tuchuang_后端_前端_注册登录
数据库·后端·网络协议·mysql·wireshark
间彧14 小时前
列式存储实现方案与关键技术框架
后端
间彧14 小时前
主流OLAP工具对比分析:Kylin、Druid与ClickHouse的适用场景
后端
hui函数14 小时前
python全栈(基础篇)——day03:后端内容(字符串格式化+简单数据类型转换+进制的转换+运算符+实战演示+每日一题)
开发语言·后端·python·全栈
间彧14 小时前
SpringBoot项目实现分布式事务实战指南
后端
FIN666814 小时前
募投绘蓝图-昂瑞微的成长密码与未来布局
前端·后端·5g·云原生·信息与通信·射频工程·芯片
间彧14 小时前
分布式系统中跨服务事务一致性的实现与解决方案
后端
间彧14 小时前
OLTP场景解析:联机事务处理的核心应用领域
后端