搞懂Spring的事务传播机制

搞懂Spring的事务传播机制

事务传播枚举:
org.springframework.transaction.annotation.Propagation
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);

@Transactional(propagation= Propagation.REQUIRED)

结论

  使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;

如果当前存在事务,则加入这个事务,成为一个整体。

举例

 老爸没钱吃饭,儿子有钱,儿子会自己买了自己吃【哈哈,很自私】。老爸有钱吃饭,会分吃的给儿子【这叫父爱】

实验一:
com.golder.test.TransactionTest#userTransactionTest
@Test
public void userTransactionTest() {
    transactionService.testPropagationTrans();
}
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Override
public void saveParent() {
    Users users = new Users();
    users.setId("4");
    users.setUsername("saveParent");
    users.setPassword("123");
    users.setFace("saveParent");
    users.setCreatedTime(new Date());
    users.setUpdatedTime(new Date());
    usersMapper.insert(users);
}

@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}

public void saveChildren1() {
    Users users = new Users();
    users.setId("5");
    users.setUsername("saveChildren-1");
    users.setPassword("123");
    users.setFace("saveChildren");
    users.setCreatedTime(new Date());
    users.setUpdatedTime(new Date());
    usersMapper.insert(users);
}
public void saveChildren2() {
    Users users = new Users();
    users.setId("7");
    users.setUsername("saveChildren-2");
    users.setPassword("123");
    users.setFace("saveChildren-2");
    users.setCreatedTime(new Date());
    users.setUpdatedTime(new Date());
    usersMapper.insert(users);
}
分析:

  以上这种情况,saveParent()saveChildren()#saveChildren1()会成功保存数据,saveChildren2()不会被执行。也就是说,没有事务注解@Transactional时,程序不会自动回滚事务。

实验二:

  给TransactionServiceImpl#testPropagationTrans()添加事务注解@Transactional(propagation= Propagation.REQUIRED)

com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
分析:

  以上这种情况,saveParent()saveChildren()#saveChildren1()数据会被回滚。

实验三:

  其他地方不加事务注解,给UsersServiceImpl#saveChildren添加事务注解@Transactional(propagation= Propagation.REQUIRED)

com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  以上这种情况,usersService.saveParent()不会被回滚,而saveChildren()#saveChildren1()会被回滚

@Transactional(propagation = Propagation.SUPPORTS)

结论:

  如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。

举例:

  老爸没饭吃,儿子也没饭吃;老爸有饭吃,我也有饭吃。【同甘共苦】

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据不会被回滚

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据会被回滚

@Transactional(propagation = Propagation.MANDATORY)

结论:

  该传播属性强制必须存在一个事务,如果不存在,则抛出异常。

举例:

  老爸叫儿子买包烟,儿子说给跑腿费【事务】我就去,否则我不去。【前提是要有事务,否则抛个异常给你】

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  通过这个@Transactional(propagation = Propagation.MANDATORY)的源码可以知道【源码注释:Support a current transaction, throw an exception if none exists】,如果调用方没有事务,则会抛出异常(org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory')。

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  程序运行正常。但是,saveParent()saveChildren1()数据会被回滚

@Transactional(propagation = Propagation.REQUIRES_NEW)

结论:

  如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;如果当前没有,则创建一个同Propagation.REQUIRES一样的事务。

举例:

  老爸请儿子吃饭,儿子偏不要,老子有钱,为什么要你请?老子有钱吃饭。

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()不会被回滚,saveChildren1()会被回滚,因为saveChildren()会新开一个事务。

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据会被回滚。但是,saveChildren()会挂起上面传播下来的事务,自己创建了一个事务。

实验三:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
    int a = 1 / 0;
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChildren1();
    saveChildren2();
}
分析:

  saveParent()数据会被回滚,但是,saveChildren()saveChildren1()saveChildren2()数据不会被回滚,因为saveChildren()是独立的新事务。

@Transactional(propagation = Propagation.NOT_SUPPORTED)

结论:

  如果当前有事务,则把事务挂起,自己不使用事务去运行数据库操作

举例:

  老爸有钱吃饭,分点给儿子,儿子不鸟老爸,把钱放一边,这点钱能吃啥,不吃。

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据不会被回滚

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()数据会被回滚,saveChildren1()数据不会回滚,因为Propagation.NOT_SUPPORTED表示该方法不回滚事务。

@Transactional(propagation = Propagation.NEVER)

结论:

  顾名思义,never是从不的意思,即从不使用事务。如果当前有事务,则抛出异常。

举例:

  老爸叫儿子买烟,给一个亿的跑腿费,儿子在上分打游戏没空,不鸟他,抛个异常给他。

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  直接抛异常(org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'),这个方法saveChildren()被标记为never,调用方不能使用事务,否则就抛异常。

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据不会被回滚,道理你们都懂。

@Transactional(propagation = Propagation.NESTED)

结论:

  如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;

如果当前没有事务,则开启同Propagation.REQUIRED一样的事务。

但是如果父事务提交,则会携带子事务一起提交。

如果父事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。

举例:

  老爸带儿子出去斗地主,把钱都输光了,怕被老婆知道,让儿子一起背锅。老爸拿钱给儿子去赌一把,把钱输光了,就把责任推给儿子,让儿子一个人背锅。【老子犯错让儿子一起背锅,儿子犯错,儿子自己背锅,老子看心情理你

实验一:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()数据不会被回滚,saveChildren1()数据会被回滚,因为Propagation.NEVER会开启一个同Propagation.REQUEST一样的事务。

实验二:
com.golder.service.impl.TransactionServiceImpl#testPropagationTrans:
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    usersService.saveParent();
    usersService.saveChildren();
}
com.golder.service.impl.UsersServiceImpl#saveChildren:
@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChildren1();
    int a = 1 / 0;
    saveChildren2();
}
分析:

  saveParent()saveChildren1()数据都会被回滚,因为Propagation.NEVER会开启一个嵌套事务,是Propagation.REQUIRED的子事务,父事务可以选择不回滚当前事务,也可以选择回滚当前事务。但是,当父事务提交时,子事务也会一起提交。

总结:
1. @Transactional(propagation= Propagation.REQUIRED)
使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;
如果当前存在事务,则加入这个事务,成为一个整体。
2. @Transactional(propagation = Propagation.SUPPORTS)
如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。
3. @Transactional(propagation = Propagation.MANDATORY)
该传播属性强制必须存在一个事务,如果不存在,则抛出异常。
4. @Transactional(propagation = Propagation.REQUIRES_NEW)
如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;如果当前没有,则创建一个同Propagation.REQUIRES一样的事务。
5. @Transactional(propagation = Propagation.NOT_SUPPORTED)
如果当前有事务,则把事务挂起,自己不使用事务去运行数据库操作
6. @Transactional(propagation = Propagation.NEVER)
顾名思义,never是从不的意思,即从不使用事务。如果当前有事务,则抛出异常。
7. @Transactional(propagation = Propagation.NESTED)
如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;

如果当前没有事务,则开启同Propagation.REQUIRED一样的事务。

但是如果父事务提交,则会携带子事务一起提交。

如果父事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨润泽林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值