Spring事务的传播机制以及手动回滚

一、事务简介

事务的ACID(原子性,一致性,隔离性,持久性)
隔离性是有4种隔离级别(针对脏读、可重复读,幻读)
除此之外,还有七种传播机制

一提到事务,我们可能最先想到的就是数据库中的事务。如果MySQL中一个事务中某个操作失败了,那么整个事务都会回滚,变成原来的样子。

而Spring事务和数据库中的事务其实是一样的,它也是调用数据库的事物操作,回滚之类的。
因此,如果数据库没有事物,Spring事物也是无效的

Spring事务一般是针对Service的。

二、Spring事物应用场景举例

在一个service方法中,需要插入两张表A、B,两次插入插入操作必须一起成功,或者一起失败。
如下

//insertA(),insertB()必须一起成功或失败
@Override
public void insertService(T record1, T record2) {
    //插入A表
    insertA(record1);
    //插入B表
    insertB(record2);
}

实现的方式如下。

三、Spring事物实现的几种可能

1、在整个方法上加@Transactional(不必在单个方法中加):

@Transactional
public void insertService(T record1, T record2) {
    //插入A表
    insertA(record1);
    //插入B表
    insertB(record2);
}

2、在单个方法上加@Transactional:

//注意,这两个方法一定和insertService()不在同一个类中!
@Transactional(propagation=PROPAGATION_MANDATORY)
public Long insertA(T record);

@Transactional(propagation=PROPAGATION_MANDATORY)
public Long insertB(T record);

如果是REQUIRED级别就无效,必须是MANDATORY级别
3、在整个方法及单个方法上加@Transactional(解释事务传播最经典的案例):

class X{
    @Transactional
    public void insertService(T record1, T record2) {
        //插入A表
        insertA(record1);
        //插入B表
        insertB(record2);
    }
}

class Y{
    //注意,这两个方法一定和insertService()不在同一个类中!
    @Transactional
    public Long insertA(T record);

    @Transactional
    public Long insertB(T record);
}

这三种方法可能有点让人难以理解,下面是对此的说明。

四、Spring事物的传播机制

这两种方法工作的原理就涉及到事物的传播机制。
Spring默认的传播机制是:REQUIRED。

它的规则是:这个方法必须运行在事务中,如果事务存在,则会运行在当前事务中,否则会新开一个事务。

有点晦涩难懂,但其实也很好理解,结合上面两种方法解释就是:

  • 对整个方法加事物——程序调用insertService()方法时,发现它有事物注解,便会创建一个事物,将这个方法加入到事物之中。
  • 对单个插入加事物——程序运行到insertA(),发现这个方法是有MANDATORY级别的事物注解,继续运行发现insertB()也有MANDATORY级别的事物注解,便会认为,两个事务必然是同时成功或失败。
  • 对整个及单个加事物——程序运行到insertService()方法,发现这个方法是有事物注解,便会创建一个事物,把它加入进入。继续运行发现insertA()也有事务,但在事务之中,就不会再创建事务了,insertB()也是同理。

对于对三种,也就是insertService 与 insertA、insertB 都加了事务,如果insertA 和insertB 加了try catch 捕捉了异常,不抛出异常给insertService 会导致报错

想要了解其他几种事物传播机制的话:
传送门

五、Spring事务失效的场景

场景是这样,同一个类中,一个方法调用另一个事务注释的方法。

class{
    public void insertService(T record1, T record2) {
        //插入A表
        insertA(record1);
        //插入B表
        insertB(record2);
    }

    //注意,这两个方法和insertService()在同一个类中
    @Transactional
    public Long insertA(T record);

    @Transactional
    public Long insertB(T record);
}

这时候, insertA() 和 insertB() 的事物是不生效的。
原因是:
Spring采用动态代理机制来实现事务控制。在扫描bean时,会对@Transactional 注解的bean生成一个代理子类,实际上调用insertA() 或 insertB() 时,会自动调用代理对象中实现的方法,代理里的方法才是有事务的!而对象内部的方法相互调用,是不会走代理的,默认是this.insertA() 也就是本对象的。

六、Spring事务的xml配置方式

    <!-- 配置spring的声明式事务 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
     <!-- 事务注解驱动,标注@Transactional的类和方法将具有事务性 -->  
	<tx:annotation-driven transaction-manager="transactionManager" /> 
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="find*" propagation="SUPPORTS"/>
            <tx:method name="*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
     
    <!--支持基于注解的aspectj -->
    <aop:aspectj-autoproxy />
    <aop:config>
        <aop:pointcut expression="execution(* com.fengyuan.service.*.*(..))" id="mypoint"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/>
    </aop:config>

七、Spring事物的回滚

手动回滚操作如下:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

注意事项:

1、配置spring和springMVC扫描包的时候,一定要明确,springMVC只负责扫描controller层,不要扫描需要配置事物回滚的Service层,这是因为在加载配置时springMVC的配置先于spring,这样的话当spring扫描包的时候发现已经存在(被springMVC先扫描创建了),那么就不会创建对象,因为是由springMVC扫描创建的,自然也就不会使用spring的事物代理,就不能进行回滚。

2、spring事物回滚默认只有在程序出现RuntimeException的时候才进行回滚;

3、如果需要其他异常回滚,那么可以使用如下方式:

//使用rollbackFor(回滚指定的异常)
@Transactional(rollbackFor={Exception.class})

参考:
传送门1

传送门2

传送门3

发布了67 篇原创文章 · 获赞 32 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_43751710/article/details/91410592