【spring核心】Spring中的事务控制和事务失效

事务控制

在后端开发中,控制事务 是一个很常见也很重要的点。
因为我们经常会遇到多个操作的集合 需要帮他们封装成一个原子性的操作。这也就是事务的核心意义。

spring事务的原理:AOP

(不懂AOP的去看篇:理解AOP)

我们知道AOP的原理是什么:就是创建一个代理对象 来包裹原有的对象。 然后对原有对象进行增强。

所以我们的要一个方法进行事务增强。

道理是一样的 就是创建一个代理对象 在这个代理对象里面 对原方法进行事务的控制。

具体怎么做呢 我们展示一下 比较常见的注解 来实现

声明式事务

@Transactional
public void doTransactionalOperation() {
    // 事务操作的代码
}

这个注解有四个属性 很重要:

隔离级别(Isolation)

:用于控制事务之间的隔离程度,即一个事务的操作对其他事务的可见性和影响。常见的隔离级别有:

READ_UNCOMMITTED(读取未提交):最低的隔离级别,允许事务读取未提交的数据,可能会导致脏读(Dirty Read)。
READ_COMMITTED(读取已提交):允许事务读取已提交的数据,避免脏读,但可能会导致不可重复读(Non-repeatable Read)。
REPEATABLE_READ(可重复读):确保在事务执行期间多次读取同一数据时,数据保持一致,避免不可重复读,但可能会导致幻读(Phantom Read)。
SERIALIZABLE(串行化):最高的隔离级别,强制事务串行执行,避免脏读、不可重复读和幻读,但性能较低。

传播行为(Propagation)

:用于控制事务的传播方式,即事务方法调用其他事务方法时的行为。常见的传播行为有:

REQUIRED(默认值):如果当前存在事务,就加入到当前事务中,如果不存在事务,则创建一个新的事务。
REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则挂起当前事务。
SUPPORTS:如果当前存在事务,就加入到当前事务中,如果不存在事务,则以非事务方式执行。
NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务。
MANDATORY:必须在一个已存在的事务中执行,否则抛出异常。
NEVER:必须在一个非事务环境中执行,否则抛出异常。

只读属性(ReadOnly)

:用于指定事务是否为只读事务。如果设置为只读事务,事务期间不允许对数据进行修改操作,可以提升一定的性能。

超时时间(Timeout)

:用于指定事务的超时时间,即事务在指定的时间内必须完成,否则将被强制回滚。超时时间一般以秒为单位。


其他三个都好理解 我们重点说一下 这个传播行为:
新手第一次接触可能会绕住,这一篇中先省略,后面专门写一篇:
【spring核心】Spring中的事务传播
来细讲

事务失效

什么情况下事务会失效?? 我总结一下比较常见的四种场景

  • @Transactional 修饰私有方法的时候 可能会失效 (注意这里时可能)
    JDK动态代理只能代理实现了接口的类的公共方法,无法代理私有方法。因此,当我们在私有方法上添加@Transactional注解时,由于动态代理的限制,事务注解不会被织入到代理对象中,导致事务管理失效。
  • 只有代理对象 调用才会生效
    这个是我们平常遇到的最多的情况
    注意:

如果在同一个类中的方法调用,且这些方法都在同一个类的实例上调用,而且这些方法都没有被 @Transactional 或者类级别的 @Transactional 注解修饰,那么 Spring 事务将不会生效。

Spring 事务是通过 AOP(面向切面编程)来实现的。通常情况下,Spring 在对带有 @Transactional 注解的方法进行代理时,会在方法调用前开启事务,在方法调用后根据方法的执行情况来决定提交或回滚事务。

但是,如果在同一个类的方法调用中,事务代理并不会生效,这是因为 Spring 默认情况下使用的是基于代理的 AOP,它是通过 JDK 动态代理或者 CGLIB 来生成代理对象的。对于同一个类的方法调用,Spring 事务只会在代理对象中生效,而不会作用在同一个类的实例对象上。

什么意思呢 你通过bean注入 从容器里面取出来的对象 调用它的方法 才会生效,
如果知识一个类内部的方法 比如下面的m1 就是一个单纯的内部方法,用它去调用是不会生效的。


@Component
public class UserService {
    public void m1(){
        this.m2();
    }
    
    @Transactional
    public void m2(){
        //执行db操作
    }

如果没有获取UserService 的bean 直接外部调用m2方法 它时不会生效的。

大家在写代码 处理事务的时候 要千万注意这一点 当你的一个方法上面加了事务注解 这时候 你要留意调用这个方法的 调用者是实例对象还是代理对象

  • 异常类型错误
    并不是任何异常情况下,spring都会回滚事务,默认情况下,RuntimeException和Error的情况下,spring事务才会回滚。

也可以自定义回滚的异常类型

  • 必须在同一个线程里面
    这点也要注意 ,如果你在异常方法里面 新new了一个线程,
    那么事务也会失效
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值