前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring的七种事务

Spring的七种事务

作者头像
关忆北.
发布2021-12-07 16:50:15
2250
发布2021-12-07 16:50:15
举报
文章被收录于专栏:关忆北.关忆北.

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

PROPAGATION_REQUIRED

image-20210709144540449
image-20210709144540449

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

场景一:外部不开启事务
代码语言:javascript
复制
@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();
    }

}

验证方法一、

代码语言:javascript
复制
@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();
}

验证方法二、

代码语言:javascript
复制
    @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:外部开启事务

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

代码语言:javascript
复制
   @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
image-20210708212446958

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

场景一:外部不开启事务

Service1

代码语言:javascript
复制
@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

代码语言:javascript
复制
@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();
    }
}

验证方法一、

代码语言:javascript
复制
    @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();
    }

验证方法二、

代码语言:javascript
复制
    @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:

代码语言:javascript
复制
    @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:

代码语言:javascript
复制
    @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:

代码语言:javascript
复制
@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
image-20210709135237991

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

@Service1

代码语言:javascript
复制
@Service
public class User1ServiceImpl implements User1Service {
    //省略其他...
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addNested(User1 user){
        user1Mapper.insert(user);
    }
}

@Service2

代码语言:javascript
复制
@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();
    }
}
场景一:外围方法没有开启事务

验证方法一、

代码语言:javascript
复制
  @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();
  }

验证方法二、

代码语言:javascript
复制
    @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:外围开启事务

验证方法一、

代码语言:javascript
复制
@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();
}

验证方法二、

代码语言:javascript
复制
@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);
}

验证方法三、

代码语言:javascript
复制
@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类似的操作。

原文链接

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PROPAGATION_REQUIRED
  • PROPAGATION_REQUIRED
  • PROPAGATION_REQUIRES_NEW
  • Propagation.NESTED
  • Spring中七种事务传播行为
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档