Spring 事务特性 — @Transactional 事务注解的基本运用

6 篇文章 1 订阅

什么叫事务?

指要做的或所做的事情。指访问并可能更新数据库中各种数据项的一个程序执行单元。
在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句或者整个程序。
事务通常由高级数据库操纵语言/编程语言书写的用户程序的执行所引起,由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

事务的传播行为:

所谓事务的传播行为是指,如果在开始当前事务之前一个事务上下文已经存在此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下7个表示传播行为的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。(默认的传播行为,required
    例如:方法A调用方法B,它们用同一个事务。(如果B没有事务,它们会用同一个事务)(只要有一个回滚,整体就会回滚)
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务。“requires_new”
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    例如:方法A调用方法B,如果A没有事务,那么B就以非事务执行。如果A有事务就以A事务为准。如果A没有事务,那么B就会以非事务执行(supports)
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。not_supported
  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
    例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。never
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 mandatory
  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于Required一样。nested
    例如:方法A中调用了方法B,B中 try catch手动回滚,A不会回滚

事务的回滚机制

Spring的AOP即声明式事务管理默认是针对unchecked exception 回滚。Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback (Spring默认取决于是否抛出runtimeException)。

如果在方法中有try{}catch(Exception e){} 处理,那么try里面的代码块就脱离了事务的管理,若要事务生效需要在catch中throw new RuntimeException (“xxxxxx”); 这一点也是面试中会问到的事务失效的场景。

事务的传播行为示例

一. required

TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。(默认的传播行为,required

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
    }
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addTest(){
        testDao.addTest();
        int i = 1/0;
    }

REQUIRED表示在同一个事务:

  1. addTest异常会使得整个事务回滚,user表和test表都没插入成功。
  2. addUser异常也会使得事务回滚,user表和test表都没插入成功。
二. requires_new

TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务。“requires_new”

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
    }
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
            int i = 1/0;
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

REQUIRES_NEW表示addTest新创建了一个事务,跟addUser不在同一个事务里。两个事务互不影响。

  1. addTest异常,进行回滚。addUser没有回滚。user表插入成功,test表插入失败。
  2. addUser异常,进行回滚。addTest没有回滚。test表插入成功,user表插入失败。
三. supports

TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
例如:方法A调用方法B,如果A没有事务,那么B就以非事务执行。如果A有事务就以A事务为准。如果A没有事务,那么B就会以非事务执行(supports)

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
        int i = 1/0;
    }
@Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

如果addUser有事务,那么addTest跟addUser在同一个事务。如果addUser没有事务,那么就以非事务方式运行。

四. not_supported

TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。not_supported
例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
        int i = 1/0;
    }
@Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

如果addUser异常,会回滚。addTest不会滚。不管addUser是否有事务,addTest都以非事务方式运行。

五. mandatory

TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 mandatory

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
        int i = 1/0;
    }
@Transactional(propagation = Propagation.MANDATORY,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

如果addUser有事务,那么addTest跟addUser在同一个事务。如果addUser没有事务,那么就会报异常:No existing transaction found for transaction marked with propagation ‘mandatory’

六. never

TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。never

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
        int i = 1/0;
    }
@Transactional(propagation = Propagation.NEVER,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

如果addUser没有事务,addTest以非事务方式运行。如果addUser有事务,addTest就会报错:Existing transaction found for transaction marked with propagation ‘never’
never和mandatory正好相反。

七. nested

TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于Required一样。nested
例如:方法A中调用了方法B,B中 try catch手动回滚,A不会回滚

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void addUser(){
        userDao.addUser();
        testService.addTest();
    }
@Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public void addTest(){
        try {
            testDao.addTest();
            int i = 1/0;
        } catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

addUser的事务内嵌addTest的事务,如果addUser异常回滚,那么addTest也会回滚。如果addTest回滚,addUser不会回滚。

  • nested和requires_new的不同是:
    1. nested内层事务回滚不影响外层,外层事务回滚影响内层跟着回滚。
    2. requires_new外层和内层不是同一个事务,互不影响。外层回滚不影响内层,内层回滚不影响外层。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值