Spring中的事务是如何实现的

在使用Spring框架进行开发时,事务管理是一个非常重要的功能,可以确保数据的一致性和完整性。但有时候我们会遇到事务失效的情况,导致数据不一致或者丢失。本文将探讨Spring事务的特性和常见问题。

1. 事务的基本特性和隔离级别

事务基本特性ACID分别是:

  • 原子性:指的是一个事务中的操作要么全部成功,要么全部失败。
  • 一致性:指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。比如A转账给B100块钱,假设A只有90块,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证
  • 隔离性:指的是一个事务的修改在最终提交前,对其他事务是不可见的。
  • 持久性:指的是一旦事务提交,所做的修改就会永久保存到数据库中。

隔离性有4个隔离级别,分别是:

  • read uncommit  读未提交,可能会读到其他事务未提交的数据,也叫做脏读。 用户本来应该读取到id=1的用户age应该是10,结果读取到了其他事务还没有提交的事务,结果读取结果age=20,这就是脏读。
  • read commit  读已提交,两次读取结果不一致,叫做不可重复读。 不可重复读解决了脏读的问题,他只会读取已经提交的事务。 用户开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里同一个查询读取到不同的结果叫做不可重复读。
  • repeatable read  可重复复读,这是mysql的默认级别,就是每次读取结果都一样,但是有可能产生幻读。
  • serializable  串行,一般是不会使用的,他会给每一行读取的数据加锁,会导致大量超时和锁竞争的问题。

2. Spring中的事务是如何实现的

  1. Spring事务底层是基于数据库事务和AOP机制的
  2. 首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean
  3. 当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解
  4. 如果加了,那么则利用事务管理器创建一个数据库连接
  5. 并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步
  6. 然后执行当前方法,方法中会执行sql
  7. 执行完当前方法后,如果没有出现异常就直接提交事务
  8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
  9. Spring事务的隔离级别对应的就是数据库的隔离级别
  10. Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的
  11. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开一个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql

3. Spring事务失效的八大场景与原因分析

1. 嵌套调用问题

在Spring中,如果在同一个类中的两个方法A和B都被声明为事务,并且A调用了B,但是B的事务并没有生效。这种情况可能是因为Spring默认使用基于代理的事务管理,而嵌套调用的方法B实际上是被同一个类中的方法A调用的,并没有经过代理对象的处理。

2. 异常处理问题

如果一个事务方法内部抛出了一个RuntimeException,并且没有捕获处理,那么事务将会回滚。但是如果异常被捕获并在方法内部处理了,事务就不会回滚。这可能导致事务失效,因为异常被处理了,但是事务却没有被回滚。

3. 多个数据源问题

在使用多个数据源时,如果一个方法同时操作了两个数据源,而这两个数据源分别开启了事务,那么事务管理器无法同时管理这两个事务,可能导致其中一个事务失效。

4. 异步方法问题

在Spring中,如果一个事务方法内部调用了一个带有@Async注解的异步方法,那么异步方法将在一个新的线程中执行,而且不会受到外部事务的管理。这可能导致异步方法内部的数据库操作失效。

5. 同一个类内部调用问题

如果在同一个类中的一个事务方法直接调用了另一个事务方法,那么事务不会生效。这是因为Spring默认使用基于代理的事务管理,而在同一个类内部方法调用是不会经过代理对象的。

6. 事务方法修饰符问题

在Spring中,事务方法的修饰符必须是public,否则事务将不会生效。如果事务方法的修饰符不是public,那么事务管理器无法代理该方法,导致事务失效。

7. 未使用@Transactional注解问题

在Spring中,如果一个方法没有被@Transactional注解修饰,那么该方法将不会被事务管理器管理,可能导致事务失效。

8. 子方法调用问题

在Spring中,如果一个事务方法内部调用了另一个非事务方法,那么事务将会失效。这是因为Spring默认只对带有@Transactional注解的方法进行事务管理,而非事务方法不会被代理对象管理。

更多文章:

深入理解Mysql事务隔离级别与锁机制-CSDN博客

如何解决缓存一致性的问题-CSDN博客

Spring之Bean生命周期源码解析-CSDN博客

MySQL 存储引擎和索引类型介绍-CSDN博客

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Memory_2020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值