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 当前存在事务就报错
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;
如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
@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开启的),于是将自己加入到已经存在的事务里面
@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)]
@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)]
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中
存在事务,则加入当前事务,不存在事务,就以非事务方法执行
@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)]
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时发现没有事务,所以以非事务的方式运行
存在事务,则加入当前事务,不存在事务,则抛出异常。
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);
}
No existing transaction found for transaction marked with propagation 'mandatory'
存在事务,则挂起该事务,创建一个新事务,不存在也会新建一个。
@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)]
@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)]
@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的事务拿不到锁.
存在事务,则挂起当前事务,以非事务方式执行
@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回退
不使用事务,如果当前事务存在,则抛出异常
@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);
}
Existing transaction found for transaction marked with propagation 'never'
如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
谁抛出异常谁回滚,如果不try addBalance的异常会传到xxxBalance导致xxxBalance也回滚
@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)]