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

  • Post author:
  • Post category:其他




什么叫事务?

指要做的或所做的事情。指访问并可能更新数据库中各种数据项的一个程序执行单元。

在关系数据库中,一个事务可以是一条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外层和内层不是同一个事务,互不影响。外层回滚不影响内层,内层回滚不影响外层。



版权声明:本文为weixin_43934626原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。