Spring的七种事务

Posted 爱叨叨的程序狗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring的七种事务相关的知识,希望对你有一定的参考价值。

官方文档注释说明七种事务

PROPAGATION_REQUIRED

image-20210709144540449

支持当前事务,如果不存在则创建一个新事务。最常用的选择

场景一:外部不开启事务
@Service
public class User1ServiceImpl implements User1Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User1 user){
        user1Mapper.insert(user);
    }
}
@Service
public class User2ServiceImpl implements User2Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User2 user){
        user2Mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequiredException(User2 user){
        user2Mapper.insert(user);
        throw new RuntimeException();
    }

}

验证方法一、

@Override
public void notransaction_exception_required_required(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addRequired(user1);

    User2 user2=new User2();
    user2.setName("李四");
    user2Service.addRequired(user2);

    throw new RuntimeException();
}

验证方法二、

    @Override
    public void notransaction_required_required_exception(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequired(user1);

        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiredException(user2);
    }

方法1、2的抛出异常位置不同

output

一:张三、李四均插入成功。各自进行事务,异常在外抛出,不影响单独事务。

二:张三成功,李四不成功,李四自己方法抛出异常回滚。

结论:在外围方法未开启事务的情况下,PROPAGATION_REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

PROPAGATION_REQUIRED

场景2:外部开启事务

开发中使用较高的场景(默认情况)

   @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_exception_required_required(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequired(user1);

        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequired(user2);

        throw new RuntimeException();
    }

output

结论:外围开启事务,出现异常均回滚。原因是外围开启事务,PROPAGATION_REQUIRED修饰的所有内部方法会加入到外围方法的事务中,内部事务和外部事务均属于同一个事务。

PROPAGATION_REQUIRES_NEW

image-20210708212446958

创建一个新事务,如果当前事务存在,则暂停当前事务

场景一:外部不开启事务

Service1

@Service
public class User1ServiceImpl implements User1Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequiresNew(User1 user){
        user1Mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequired(User1 user){
        user1Mapper.insert(user);
    }
}

Service2

@Service
public class User2ServiceImpl implements User2Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequiresNew(User2 user){
        user2Mapper.insert(user);
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequiresNewException(User2 user){
        user2Mapper.insert(user);
        throw new RuntimeException();
    }
}

验证方法一、

    @Override
    public void notransaction_exception_requiresNew_requiresNew(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequiresNew(user1);
        
        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiresNew(user2);
        throw new RuntimeException();
    }

验证方法二、

    @Override
    public void notransaction_requiresNew_requiresNew_exception(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequiresNew(user1);
        
        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiresNewException(user2);
    }

验证方法1:外围方法没有事务,插入“张三”、“李四”方法都在自己的事务中独立运行,外围方法抛出异常回滚不会影响内部方法。

验证方法2:张三正常插入,李四无法插入,李四在自己的方法中开启新事务,但是抛出异常回滚。

场景2:外部开启事务

验证方法1:

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_exception_required_requiresNew_requiresNew(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequired(user1);
        
        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiresNew(user2);
        
        User2 user3=new User2();
        user3.setName("王五");
        user2Service.addRequiresNew(user3);
        throw new RuntimeException();
    }

验证方法2:

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void transaction_required_requiresNew_requiresNew_exception(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequired(user1);
        
        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiresNew(user2);
        
        User2 user3=new User2();
        user3.setName("王五");
        user2Service.addRequiresNewException(user3);
    }

验证方法3:

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void transaction_required_requiresNew_requiresNew_exception_try(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addRequired(user1);
    
    User2 user2=new User2();
    user2.setName("李四");
    user2Service.addRequiresNew(user2);
    User2 user3=new User2();
    user3.setName("王五");
    try {
        user2Service.addRequiresNewException(user3);
    } catch (Exception e) {
        System.out.println("回滚");
    }
}

结论:外围方法开启事务的情况下,**Propagation.REQUIRES_NEW**修饰的内部方法全部单独开启独立事务,不同的内部方法、外部事务间相互独立,互不干扰。

Propagation.NESTED

image-20210709135237991

如果当前事务存在,则在嵌套事务中执行。

@Service1

@Service
public class User1ServiceImpl implements User1Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNested(User1 user){
        user1Mapper.insert(user);
    }
}

@Service2

@Service
public class User2ServiceImpl implements User2Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNested(User2 user){
        user2Mapper.insert(user);
    }
    
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNestedException(User2 user){
        user2Mapper.insert(user);
        throw new RuntimeException();
    }
}
场景一:外围方法没有开启事务

验证方法一、

  @Override
  public void notransaction_exception_nested_nested(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addNested(user1);

    User2 user2=new User2();
    user2.setName("李四");
    user2Service.addNested(user2);
    throw new RuntimeException();
  }

验证方法二、

    @Override
    public void notransaction_required_required_exception(){
        User1 user1=new User1();
        user1.setName("张三");
        user1Service.addRequired(user1);

        User2 user2=new User2();
        user2.setName("李四");
        user2Service.addRequiredException(user2);
    }

方法一均插入,张三、李四是在各自的独立事务中运行。

方法二张三插入,李四未插入,李四报异常回滚。两者事务独立,不影响张三。

场景2:外围开启事务

验证方法一、

@Transactional
@Override
public void transaction_exception_nested_nested(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addNested(user1);
    
    User2 user2=new User2();
    user2.setName("李四");
    user2Service.addNested(user2);
    throw new RuntimeException();
}

验证方法二、

@Transactional
@Override
public void transaction_nested_nested_exception(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addNested(user1);
    
    User2 user2=new User2();
    user2.setName("李四");
    user2Service.addNestedException(user2);
}

验证方法三、

@Transactional
@Override
public void transaction_nested_nested_exception_try(){
    User1 user1=new User1();
    user1.setName("张三");
    user1Service.addNested(user1);
    
    User2 user2=new User2();
    user2.setName("李四");
    try {
        user2Service.addNestedException(user2);
    } catch (Exception e) {
        System.out.println("方法回滚");
    }
}

验证1,2由于外部开启事务,内部嵌套事务相当于外部事务的子事务,子事务回滚影响外部事务回滚。

验证方法3:张三插入,李四未插入,内部事务为外围事务的子事务,外围方法开启事务,插入“李四”内部方法抛出异常,可以单独对子事务回滚。

结论:外围方法开启事务的情况下**Propagation.NESTED**修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务。

Spring中七种事务传播行为

事务传播行为类型说明
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

原文链接

以上是关于Spring的七种事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring事务的七种传播行为

Spring事务的七种传播行为

Spring的七种事务传播机制

事物的七种传播行为

分布式事务最经典的七种解决方案

分布式事务最经典的七种解决方案