前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring之事务的传播行为实操篇

Spring之事务的传播行为实操篇

作者头像
九转成圣
发布2024-04-10 18:35:56
940
发布2024-04-10 18:35:56
举报
文章被收录于专栏:csdncsdn

Spring之事务的传播行为

枚举

代码语言:javascript
复制
public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

辅助记忆:REQUIRED+REQUIRES_NEW+NESTED+SUPPORTS/NOT_SUPPORTED+MANDATORY/NEVER

REQUIRED:有就加入,没有就新建

REQUIRES_NEW 有没有都会创建一个,有就把原来的挂起

NESTED 有就嵌套,没有就新建

SUPPORTS 有事务就加入,没有事务就以非事务的方式运行

NOT_SUPPORTED 有就挂起,然后以非事务的方式运行

MANDATORY 当前不存在事务就报错

NEVER 当前存在事务就报错

建表

代码语言:javascript
复制
CREATE TABLE `propagation_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `balance` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

默认REQUIRED

如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务

代码语言:javascript
复制
@Transactional
public void xxxBalance(){
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance>=10) {
        propagationTest.setBalance(balance-10);
        propagationTestMapper.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional
public void addBalance(){
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    propagationTest.setBalance(propagationTest.getBalance()+100);
    propagationTestMapper.update(propagationTest);
    throw new RuntimeException("");
}

结果:[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=100)]

分析:线程执行到addBalance时发现已经有事务了(xxxBalance开启的),于是将自己加入到已经存在的事务里面

头晕了吧

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    try {
        propagationTestServiceImpl.addBalance();
    } catch (Exception e) {

    }
}

@Transactional(propagation = Propagation.REQUIRED)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=100)]

情理之中吧

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
    try {
    } catch (Exception e) {

    }
}

@Transactional(propagation = Propagation.REQUIRED)
public void addBalance() {
    try {
        PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
        propagationTest.setBalance(propagationTest.getBalance() + 100);
        propagationTestMapper.update(propagationTest);
        int i = 10 / 0;
        propagationTest = propagationTestMapper.selectByPrimaryKey(2);
        propagationTest.setBalance(propagationTest.getBalance() + 50);
        propagationTestMapper.update(propagationTest);
    } catch (Exception e) {

    }

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=200)]

以前理解错了吧

代码语言:javascript
复制
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.REQUIRED)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=90), PropagationTest(id=2, balance=100)]

分析:当线程执行到addBalance时发现没有事务,于是就新建一个事务,以事务的方式运行

误区:xxxBalance没有事物,给xxxBalance新建一个事务,将addBalance加入到xxxBalance中

SUPPORTS

存在事务,则加入当前事务,不存在事务,就以非事务方法执行

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.SUPPORTS)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=100)]

代码语言:javascript
复制
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.SUPPORTS)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=90), PropagationTest(id=2, balance=200)]

分析:当线程执行到addBalance时发现没有事务,所以以非事务的方式运行

MANDATORY

存在事务,则加入当前事务,不存在事务,则抛出异常。

代码语言:javascript
复制
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.MANDATORY)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    //        int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);
}
public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}
代码语言:javascript
复制
No existing transaction found for transaction marked with propagation 'mandatory'

REQUIRES_NEW

存在事务,则挂起该事务,创建一个新事务,不存在也会新建一个。

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=100)]

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    try {
        propagationTestServiceImpl.addBalance();
    } catch (Exception e) {

    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

结果:[PropagationTest(id=1, balance=90), PropagationTest(id=2, balance=100)]

惊不惊喜

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    //        int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);
}
public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

分析:xxxBalance存在事务了,把xxxBalance的事务挂起(事务并没有提交或者回滚),addBalance新开了一个事务,但是更新的是同一行数据,导致addBalance的事务拿不到锁.

NOT_SUPPORTED

存在事务,则挂起当前事务,以非事务方式执行

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

[PropagationTest(id=1, balance=100), PropagationTest(id=2, balance=200)]

分析:xxxBalance的事务先挂起,addBalance以非事务的方式运行,+100后报错,错误传递到xxxBalance,因为xxxBalance是以事务的方式运行的,故xxxBalance回退

NEVER

不使用事务,如果当前事务存在,则抛出异常

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    propagationTestServiceImpl.addBalance();
}

@Transactional(propagation = Propagation.NEVER)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    // int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);
}
public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}
代码语言:javascript
复制
 Existing transaction found for transaction marked with propagation 'never'

NESTED

如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)

谁抛出异常谁回滚,如果不try addBalance的异常会传到xxxBalance导致xxxBalance也回滚

代码语言:javascript
复制
@Transactional
public void xxxBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(1);
    Integer balance = propagationTest.getBalance();
    if (balance >= 10) {
        propagationTest.setBalance(balance - 10);
        propagationTestServiceImpl.update(propagationTest);
    }
    try {
        propagationTestServiceImpl.addBalance();
    } catch (Exception e) {

    }
}

@Transactional(propagation = Propagation.NESTED)
public void addBalance() {
    PropagationTest propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 100);
    propagationTestMapper.update(propagationTest);
    int i = 10 / 0;
    propagationTest = propagationTestMapper.selectByPrimaryKey(2);
    propagationTest.setBalance(propagationTest.getBalance() + 50);
    propagationTestMapper.update(propagationTest);

}

public void update(PropagationTest propagationTest) {
    propagationTestMapper.update(propagationTest);
}

运行结果:[PropagationTest(id=1, balance=90), PropagationTest(id=2, balance=100)]

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring之事务的传播行为
  • 枚举
  • 建表
  • 默认REQUIRED
    • 头晕了吧
      • 情理之中吧
        • 以前理解错了吧
        • SUPPORTS
        • MANDATORY
        • REQUIRES_NEW
          • 惊不惊喜
          • NOT_SUPPORTED
          • NEVER
          • NESTED
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档