当前位置:网站首页>事务的传播机制
事务的传播机制
2022-07-31 05:50:00 【m0_67402731】
目录
事务的传播机制有7种,如下图所示:

1.形象说明:
为了更好的理解,下面我们形象的说明一下几种传播机制是什么意思:
比如你下班回家,有以下几种场景
0.REQUIRED ------ 就是如果老婆做饭了,你就吃老婆做的饭;如果老婆没有做饭,你就自己做饭吃,反正你就是要吃饭(反正要在事务中运行);
1.SUPPORTS ------ 如果老婆做饭了,你就吃老婆做的饭;如果老婆没有做饭,你就不吃(不一定非要在事务中运行);
2.MANDATORY ------ 非要吃老婆做的饭,老婆要是没有做饭,你就大发脾气,典型的家暴男;
3.REQUIRES_NEW ------ 劳资非要吃自己做的饭,就算老婆把饭做好了,你也不吃老婆做的;
4.NOT_SUPPORTED ------ 劳资就是不吃饭,就算老婆把饭做好了,我也不吃;
5.NEVER ------ 劳资就是不吃饭,如果老婆把饭做好了,我还要发脾气;
6.NESTED ------ 暂不做解释,后面会详解;
本文主要是想用代码实现这几种传播机制的具体使用;
2.代码演示:
有两张表:
school表

student表

我们如何去测试两个方法是否使用的同一个事务呢?就看是否共用同一个数据库连接或者共用同一个会话;
2.1REQUIRED
支持使用当前事务,如果当前事务不存在,创建一个新事务。
2.1.1 验证共用一个事务
schoolService.updateSchool()方法:
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
//更新id为1的学校名称为湖南大学,地址为湖南
schoolMapper.updateByPrimaryKeySelective(school);
//调用另一个方法更新学生信息
studentService.updateStudent();
System.out.println(1/0);
}
studentService.updateStudent()方法,加了事务的,默认REQUIRED:
@Transactional
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
//更新sid为1的学生年龄为25
studentMapper.updateByPrimaryKeySelective(student);
}
如上所示:updateSchool方法是加了事务的,调用完studentService.updateStudent方法后,会报错,如果updateSchool和updateStudent共用同一个事务,updateSchool报错,自身回滚,肯定会带着updateStudent一起回滚;如果不是共用同一个事务,那么updateStudent会执行成功并提交,不会回滚;
结果:
updateSchool成功回滚了

updateStudent也成功回滚了

看过我写的深入理解@Transactional注解的使用和原理就知道,两个方法会共用同一个数据库连接,也就共用同一个事务,两个方法一起提交或者回滚;
2.1.2 验证当前没有事务,就新建一个事务
schoolService.updateSchool()方法:
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
//更新id为1的学校名称为湖南大学,地址为湖南
schoolMapper.updateByPrimaryKeySelective(school);
//调用另一个方法更新学生信息
studentService.updateStudent();
}
studentService.updateStudent()方法:
@Transactional
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
//更新sid为1的学生年龄为25
studentMapper.updateByPrimaryKeySelective(student);
//报错
System.out.println(1/0);
}
如上所示:updateSchool方法是没有加事务的,调用studentService.updateStudent方法,updateStudent方法加了事务,并且会报错,如果updateStudent没有新建事务的话,不会回滚,如果是建了事务,就会回滚;
结果:
1.控制台提示报错

2. updateSchool方法没有回滚(将北京大学刚改为湖南大学)

3.updateStudent方法回滚了(将age更新为25)

验证通过;
2.2SUPPORTS
支持使用当前事务,如果当前事务不存在,则不使用事务。
2.2.1 支持使用当前事务
updateSchool方法,加事务,更新id为1的name为“湖南大学”,location为“湖南”,输出1/0,肯定会报错的;
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
System.out.println(1/0);
}
updateStudent方法更新id为1的age为25;
@Transactional(propagation = Propagation.SUPPORTS)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
}
如上所示:updateSchool方法是加了事务的,studentService.updateStudent方法也加了事务,而且传播机制是SUPPORTS,如果updateSchool和updateStudent共用同一个事务,updateSchool报错,自身回滚,肯定会带着updateStudent一起回滚;如果不是共用同一个事务,那么updateStudent会执行成功并提交,不会回滚;
结果:
1.控制台提示报错

2.updateSchool方法回滚(将北京大学刚改为湖南大学)

3.updateStudent方法回滚(将age改为25)

显然,updateSchool和updateSchool共用同一个事务,正好验证了传播机制为supports,如果当前有事务,就支持使用当前事务;
2.2.2如果当前事务不存在,则不使用事务
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,将@Transactional注释掉了,没有加事务
//@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为SUPPORTS,打印1/0,将报错
@Transactional(propagation = Propagation.SUPPORTS)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
System.out.println(1/0);
}
如上所示:updateSchool方法没有加事务,studentService.updateStudent方法加了事务,而且传播机制是SUPPORTS,如果updateStudent没有事务,报错就不会回滚,如果有事务,就会回滚;
结果:
1.控制台报错

2.updateSchool方法没有回滚,无事务执行(无事务这个说法其实不准确,任何操作数据库肯定是有事务的);

3.updateStudent方法也没有回滚,也是无事务执行的;

显然: 事务传播机制为SUPPORTS的方法,支持使用当前事务,如果当前事务不存在,则不使用事务。
2.3MANDATORY
中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
2.3.1 支持使用当前事务
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,打印1/0,会报错;
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
System.out.println(1/0);
}
updateStudent方法更新id为1的age为25,事务传播机制为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
}
**如上所示:**updateSchool方法加事务,studentService.updateStudent方法加了事务,而且传播机制是MANDATORY,如果两者共用一个事务,都会回滚;
结果:
1.控制台报错

2.updateSchool方法回滚(将北京大学刚改为湖南大学)

3.updateStudent方法回滚(将age改为25)

显然: 传播机制为MANDATORY,如果当前有事务,就使用当前事务;
2.3.2如果当前事务不存在,则抛出Exception
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,没有事务;
//@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为MANDATORY;
@Transactional(propagation = Propagation.MANDATORY)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
}
**如上所示:**updateSchool方法没有加事务,studentService.updateStudent方法加了事务,而且传播机制是MANDATORY,就看执行到updateStudent就不会报错;
结果:
1.控制台报错

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’
2.updateSchool方法没有回滚(将北京大学刚改为湖南大学)

3.pdateStudent方法直接报错: No existing transaction found for transaction marked with propagation ‘mandatory’,传播机制为mandatory的,必须有当前事务存在,不存在就报错;
**综上:**传播机制为MANDATORY,支持使用当前事务,如果当前事务不存在,则抛出Exception。
2.4REQUIRES_NEW
新建一个新事务;如果当前事务存在,把当前事务挂起。
2.4.1 当前事务不存在,创建一个新事务
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,没有事务;
//@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为REQUIRES_NEW,打印1/0,报错;
@Transactional(propagation = Propagation.MANDATORY)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
System.out.println(1/0);
}
**如上所示:**updateSchool方法没有加事务,studentService.updateStudent方法加了事务,而且传播机制是REQUIRES_NEW,如果updateStudent方法新建了事务,打印1/0,报错就会回滚,如果没有新建事务,updateStudent方法就不会回滚;
结果:
1.控制台报错

2.updateSchool方法没有回滚,无事务执行(无事务这个说法其实不准确,任何操作数据库肯定是有事务的);

3.updateStudent方法回滚(将age改为25)

**显然:**传播机制为REQUIRES_NEW的,当前没有事务,就新建一个事务,在事务中运行;
2.4.2 新建一个事务,当前事务存在,把当前事务挂起
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,有事务,打印1/0,报错;
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
System.out.println(1/0);
}
updateStudent方法更新id为1的age为25,事务传播机制为REQUIRES_NEW;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
}
**如上所示:**updateSchool方法有加事务,studentService.updateStudent方法加了事务,而且传播机制是REQUIRES_NEW,如果updateStudent方法新建了另一个事务,updateSchool报错,updateStudent不会回滚,如果不是新建一个事务而是共用一个事务,就会一起回滚;
结果:
1.控制台报错

2.updateSchool方法回滚(将北京大学刚改为湖南大学)

3.updateStudent没有回滚(将age改为25)

**显然:**updateStudent新建了另外一个事务,和updateSchool并不是共用一个事务;
**总结:**传播机制是REQUIRES_NEW,新建一个新事务;如果当前事务存在,把当前事务挂起。
使用场景:被调用方法,不想因为调用方出错而回滚,可以使用REQUIRES_NEW;
2.5NOT_SUPPORTED
无事务执行,如果当前事务存在,把当前事务挂起。
2.5.1 无事务执行
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,没有事务,打印1/0,报错;
//@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为NOT_SUPPORTED;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
System.out.println(1/0);
}
**如上所示:**updateSchool方法没有事务,studentService.updateStudent方法加了事务,而且传播机制是NOT_SUPPORTED,如果updateStudent没有事务,那么在执行打印1/0报错后,也就不会回滚;
结果:
1.控制台报错

2.updateSchool方法不回滚(将北京大学刚改为湖南大学)

3.updateStudent没有回滚(将age改为25)

**显然:**两个方法都没有在事务中运行,都没有回滚,所以,如果当前没有事务,NOT_SUPPORTED并不会新建一个事务,也是无事务执行;
2.5.2如果当前事务存在,把当前事务挂起。
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,有事务;
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为NOT_SUPPORTED,打印1/0,报错;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
System.out.println(1/0);
}
**如上所示:**updateSchool方法有事务,studentService.updateStudent方法加了事务,而且传播机制是NOT_SUPPORTED,如果updateStudent没有事务,那么在执行打印1/0报错后,也就不会回滚,而updateSchool检测到报错,如果当前事务有效,updateSchool就会回滚;
结果:
1.控制台报错

2.updateSchool方法回滚(将北京大学刚改为湖南大学)

3.updateStudent没有回滚(将age改为25)

**显然:**当前有事务的情况下,传播机制为NOT_SUPPORTED的方法无事务运行;
**总结:**事务传播机制为NOT_SUPPORTED,无事务执行,如果当前存在事务,把当前事务挂起;
**使用场景:**被调用方法想无事务运行,但又不影响调用方的事务,可以用NOT_SUPPORTED;
2.6NEVER
无事务执行,如果当前有事务则抛出Exception。
这个和MANDATORY就是两个完全相反的极端,一个强制不要事务,一个强制要事务,不满足都会报错;
2.6.1 无事务执行
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,没有事务;
//@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为NEVER,打印1/0,报错;
@Transactional(propagation = Propagation.NEVER)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
System.out.println(1/0);
}
**如上所示:**updateSchool方法没有事务,studentService.updateStudent方法加了事务,而且传播机制是NEVER,打印1/0,会报错,如果updateStudent是无事务执行,那么就不会回滚
结果:
1.控制台报错

2.updateSchool方法不回滚(将北京大学刚改为湖南大学)

3.updateStudent没有回滚(将age改为25)

**显然:**updateSchool和updateStudent都没有回滚,都是无事务执行,所以,传播机制为NEVER,如果当前没有事务,则无事务执行;
2.6.2如果当前有事务则抛出Exception
updateSchool方法更新id为1的name为“湖南大学”,location为“湖南”,有事务;
@Transactional
public void updateSchool(){
School school = new School();
school.setId(1);
school.setName("湖南大学");
school.setLocation("湖南");
schoolMapper.updateByPrimaryKeySelective(school);
studentService.updateStudent();
}
updateStudent方法更新id为1的age为25,事务传播机制为NEVER;
@Transactional(propagation = Propagation.NEVER)
public void updateStudent(){
Student student = new Student();
student.setSid(1);
student.setAge(25);
studentMapper.updateByPrimaryKeySelective(student);
}
**如上所示:**updateSchool方法有事务,studentService.updateStudent方法加了事务,而且传播机制是NEVER,当前有事务,就看执行updateStudent方法时到底报不报错;
结果:
1.控制台报错

2.updateSchool方法回滚(将北京大学刚改为湖南大学)

3.updateStudent直接报错
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’
**显然:**传播机制为NEVER,如果当前有事务,则报错;
总结:这种传播机制感觉没啥用途,哈哈,反正我是基本没用过;
2.7NESTED
嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
这个直接说,如果父事务回滚,子事务也会跟着回滚;如果子事务回滚,并抛出异常,父事务肯定会跟着回滚;
如果当前没有事务,就和REQUIRED,新建一个事务运行;
关于@Transactional注解的原理和事务传播机制的原理可以看我上一篇文章:
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
边栏推荐
猜你喜欢

进程和计划任务管理

浅层了解欧拉函数

【 TA - frost Wolf _may - "one hundred plan" 】 art 2.3 hard surface

Foreign trade website optimization - foreign trade website optimization tutorial - foreign trade website optimization software

接口报错no message avaliable

postgresql源码学习(34)—— 事务日志⑩ - 全页写机制

(border-box)盒子模型w3c、IE的区别

引导过程和服务控制

Explain the example + detail the difference between @Resource and @Autowired annotations (the most complete in the entire network)

熟悉而陌生的新朋友——IAsyncDisposable
随机推荐
Database Principles Homework 2 — JMU
熟悉而陌生的新朋友——IAsyncDisposable
leetcode 406. Queue Reconstruction by Height
高并发与多线程之间的难点对比(容易混淆)
(border-box) The difference between box model w3c and IE
安装和使用uView
什么是浮动?什么是文档流?清除浮动的几种方式及原理?什么是BFC,如何触发BFC,BFC的作用
DDL+DML+DQL
如何在uni-app中选择一个合适的UI组件库
LVM和磁盘配额
测试 思维导图
Analysis of pseudo-classes and pseudo-elements
Analysis of the implementation principle and detailed knowledge of v-model syntactic sugar and how to make the components you develop support v-model
DNS域名解析服务
nohup原理
What is float?What is document flow?Several ways and principles of clearing floats?What is BFC, how to trigger BFC, the role of BFC
Redux状态管理
试题 历届真题 错误票据【第四届】【省赛】【B组】
磁盘管理与文件系统
2022.7.29 数组