搞懂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一样的事务。
但是如果父事务提交,则会携带子事务一起提交。
如果父事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。