springboot事务

目录

1、事务介绍 

2、springboot事务流程 

3、springboot中的事务的传播特性 

4、springboot中的事务的隔离性 mysql 的事务隔离级别:Repeatable Read 

5、readOnly属性 (默认false) 

6、其他属性 

7、在SpringBoot2.0中使用使用需要注意的地方。 

参考:


1、事务介绍 

1.1事务 

              应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。 

1.2 事务的特征ACID 

          (1)原子性Atomicity:一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。 

          (2)一致性Consistency:事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。 

          (3)隔离性Isolation:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 

          (4)持久性Durability:持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。 

2、springboot事务流程 

1.1 当@Transactional注解的方法被类外部的代码调用时,Spring在运行时为方法所在类生成一个AOP代理对象。 代理对象根据@Transactional的属性,决定是否由事务拦截器TransactionInterceptor对此方法进行事务拦截。在进行事务拦截时,会先开启事务,然后执行业务代码,根据执行是否出现异常,通过抽象事务管理器AbstractPlatformTransactionManager来进行rollback或者commit。 

1.2    在进行方法调用的时候,发现这个方法有事务注解,AOP首先会检测到,然后用代理类采用反射机制进行调用。 

                (1)首先调用了CglibAopProxy.intercept()方法。 

                (2)接下来调用ReflectiveMethodInvocation.proceed()方法, 

                (3)TransactionInterceptor.invoke() 

                (4)TransactionAspectSupport.invokeWithinTransaction() 

                (5)TransactionAspectSupport.createTransactionIfNecessary() 

                (6) AbstractPlatformTransactionManager.getTransaction(),创建了一个新的事务。

1.3事务回滚时机:任何的RuntimeExcetipn、Error将触发回滚,任何的checkedException不触发回滚  

3、springboot中的事务的传播特性 

3.1 Propagation.REQUIRED(默认属性):如果当前没有事务 ,则自己新建一个事务 ,子方法是必须运行在这个事务中的 ; 如果当前存在事务 , 则加入这个事务 , 成为一个整体。一般用于增删改。 

                 A、使用条件:暂时未知 

                 B、回滚策略: 

                          ① 内/外只要有报错,他俩会一起回滚。 
                          ② 只要内层方法报错抛出异常,即使外层有try-catch,该事务也会回滚。 

                理解:1、外层事务先提交 

                           2、事务1(REQUIRED),事务2(REQUIRED),事务3(REQUIRED);事务3调用事务1和事务2。那么事务1事务2事务3其实就是一个事务,只要有一个出现异常则都会回滚。 

3.2 Propagation.SUPPORTS: 如果当前有事务 , 则使用事务 ,如果当前没有事务 ,则不使用事务。适用于查询 

               A、使用条件:暂时未知 

               B、回滚策略:同REQUIRED 

                         ① 外层事务正常,内层报错,即使外层有无try-catc→ 内外层都回滚 
                         ② 外层事务异常,内层正错 → 内外层都回滚。 

                         ③ 外层无事务正常,内层报错→外层正常提交。 

3.3 Propagation.MANDATORY : 该传播属性强制必须存在一个事务,加入当前事务 ,如果不存在,则抛出异常; 

              A、使用条件:必须是事务方法调用此方法 

              B、回滚策略:同REQUIRED 

3.4 Propagation.NEVER : 以非事务方式执行,如果当前有事务存在 ,则抛出IllegalTransactionStateException异常; 

              A、使用条件:外层无事务 

              B、回滚步骤: 

                         ① 外层事务正常,内层有无报错→内外层都回滚。 

                         ② 内外层无事务,都提交。 

3.5 Propagation.NOT_SUPPORTED :以非事务方式执行,如果当前有事务 ,则把事务挂起 ; 

              A、使用条件:未知 

              B、回滚步骤: 

                         ① 外层事务正常,内层报错→外层回滚,内层提交 

                         ② 外层事务正常,内层报错,且try-catch →内外层都提交 

3.6 Propagation.REQUIRES_NEW : 如果当前有事务 ,则挂起事务 ,并且自己创建一个新的事务给自己使用; 如果当前没有事务 , 则同required一样 。这种独立的内部事务还可以声明其自己的隔离级别、超时和仅读设置,并且不继承外部事务的特征。注意:创建的新的事务先提交 

              A、使用条件:暂时未知 

              B、回滚步骤: 

                        ① 内层报错回滚,外层也回滚。外层try-catch内层的异常,外层不会回滚。 

                        ② 外层报错回滚,不影响内层。 

3.7 Propagation.NESTED : 如果当前有事务,则开启子事务(嵌套事务), 嵌套事务是独立提交或者回滚的 。 

              A:使用条件, 

                        ① JDK版本要在1.4以上,有java.sql.Savepoint。因为nested就是用savepoint来实现的。 

                        ② 事务管理器的nestedTransactionAllowed属性为true。 

                        ③ JPA、Hibernate不支持嵌套事务,jdbc3.0以上支持嵌套事务。mybatis测试支持嵌套事务 

              B、回滚步骤: 

                        ① 外层异常,内外都会回滚 

                        ② 内层异常,内外都会回滚。try-catch 子事务,内存回滚,外层不回滚 

              理解:1、如何使同一个事务中的两个子事务,是不同事务?可以使事务互不影响  REQUIRES_NEW、NESTED  

                         2、 当同一个类中 事务1(REQUIRED) 调用 事务2(NEVER),不会报错?但是事务2、1都不会执行 

                               当事务1(REQUIRED)是在类A,事务2(NEVER)是在类B,事务1调用事务2是会报错,且事务1、2都会会回滚 

4、springboot中的事务的隔离性 mysql 的事务隔离级别:Repeatable Read 

Isolation.DEFAULT(-1): 默认值,表示使用底层数据库的默认隔离级别。大部分数据库为READ_COMMITTED 

Isolation.READ_UNCOMMITTED(1):  未提交读(READ_UNCOMMITTED)是最低的隔离级别,其含义是允许一个事物读取另一个事物没提交的数据。优点在于并发能力高,适合那些对数据一致性没有要求而追求高并发的场景,最大缺点是出

现脏读。 

Isolation.READ_COMMITTED(2): 读写提交(READ_COMMITTED),一个事务只能读取另外一个事务已提交的数据,不能读取未提交的数据。该级别克服了脏读,但不可重复读。 

Isolation.REPEATABLE_READ(4):可重复读(REPEATABLE_READ),目标是克服读写提交中出现的不可重复读的现象,但会出现幻读。(幻读:两次查到的数据不一样) 

Isolation.SERIALIZABLE(8):串行化(SERIALIZABLE),是数据库最高的隔离级别,它能够完全保证数据的一致性,但性能降低了。 

◆ 脏读(dirty read):当一个事务读取另一个事务尚未提交的修改时,产生脏读。  
◆  不可重复读(non-repeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。:  
◆  幻像读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。  

对于查询: 

隔离界别 

脏读 

不可重复读 

幻读 

Read_uncommitted读写未提交的 

√ 

√ 

√ 

Read_committed 读写已提交的 

× 

√ 

√ 

Repeatable_read 可重复读 

× 

× 

√ 

serializable 

× 

× 

× 

5、readOnly属性 (默认false) 

readOnly=true表明所注解的方法或类只是读取数据。 readOnly=false表明所注解的方法或类是增加,删除,修改数据。 

理解:当前事务中如果出现了增删改语句,那么抛出异常TransientDataAccessResourceException。 

6、其他属性 

① rollbackFor属性 

Spring框架的事务管理默认地只在发生非受检异常(RuntimeException和Error)时才进行事务回滚。也就是说,当事务方法抛出受检异常(Exception中除了RuntimeException及其子类以外的)时不会进行事务回滚。怎么解决? 

                @Transactional(rollbackFor=Exception.class)就可以实现,当发生受检异常(checked exceptions)时,事务也进行回滚。 

②RollbackForClassName官方解释:派生自Throwable的类名数组。你必须引起回滚的异常类名称的可选数组。 

               这个就不用像上面的异常一样把所有的受检异常全部回滚,由你自己决定哪些需要回滚。 

③noRollbackFor官方解释:不能回滚的异常类数组 

④NoRollbackForClassName ,与上面县相反 

⑤ value/transactionManager:可选的限定词,指定要使用的事务管理器。 

7、在SpringBoot2.0中使用使用需要注意的地方。 

3.1 加@Transactional的方法不能是private和protected修饰,private会直接报编译错误,protected不会报错。但是事务不起作用。 

3.2 @Transactional可以放在Controller下面直接起作用。 

3.3 @Transactional引入包问题,她有两个包:import javax.transaction.Transactional; 和 import org.springframework.transaction.annotation.Transactional; 这两个都可以用,对比了一下他们两个的方法和属性,发现后面的比前面的强大。建议后后面的。 

3.4 @Transactional 可以注解在类上面也可以注解在方法上面。 

 以下为自己的理解----

同类中:@Transactional 用法没有其他参数 

1、一个非事务方法调用另一个事务方法方法,不生效; 

spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是@Transactional注解无效。 

可以让他生效,方法一:放在另一个类中去,方法二:获取代理对象然后,调用这个方法。 

2、一个事务方法掉调用另一个非事务方法,生效; 

出现异常,同时回滚,不管try-catch与否。 

3、一个事务方法调用另一个事务方法,生效; 

             回滚步骤:两个方法应该是同一个事务,同时回滚。 

4、同一个类中,事务方法使用普通方法调用注解了事务【NESTED或者REQUIRED_NEW】方法他不会有对应的效果。只会把它当成普通方法作为这个事务的一部分同时回滚。要想生效可以获取他的代理对象然后调用。 

5、使用场景:【不同类中或者同一类中使用代理对象 调用】 

①当事务1调用事务2时,我需要事务1的执行成功与否不影响事务2执行,但是事务2的成功与否影响事务1的执行? 

                  把事务2的传播属性设置为REQUIRED_NEW,最先执行事务2。 

② 当事务1调用事务2时,内层事务异常,内层回滚,外层不回滚? 

                  把事务2的传播属性设置为NESTED,且try-catch内层的调用。 

补充:获取代理对象的方法

@Service
@Slf4j
@EnableAspectJAutoProxy(exposeProxy = true)
public class QuizServiceImpl extends AbstractShop implements IQuizService {

    @Resource
    private QuizLogMapper quizLogMapper;

    @Resource
    private ShopManageService shopManageService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void testA(){

        QuizPO po = new QuizPO();
        po.setSubject("测试主题一");
        quizMapper.insert(po);
        System.out.println("看看数据库是否有测试主体一");

        // 开启子事务
        try{
            IQuizService iQuizService = (IQuizService) AopContext.currentProxy();
            iQuizService.testB();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(propagation = Propagation.MANDATORY )
    public void testB(){
        QuizPO po = new QuizPO();
        po.setSubject("测试主题二");
        quizMapper.insert(po);
        throw new IllegalArgumentException("我抛出了异常!看看数据库还有没有的数据!");
    }
}

参考:

           1、官方 Data Access (spring.io)  页面内搜索1.4.7 Transaction Propagation 了解事务的传播 

           2、(2条消息) Spring 注解@Transactional readOnly=true_方逸涛的专栏-CSDN博客 

           3、 深入理解 Spring 之 SpringBoot 事务原理

          4、spring,springboot之事务(事务传播机制详解、嵌套事务)_springboot事务传播机制 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值