一、背景介绍

此前在项目开发过程中,使用到了事务的传播行为。但是大多数情况下都是使用的事务默认的传播行为required。但是其实还有其他的传播行为。所以特地的回顾和学习了事务的多种传播行为。本篇博客从5w2h的角度来对事务的传播行为进行学习和实践。

二、 什么是事物的传播行为

事务的传播行为其实指的是事务在多个方法之间的传播方式和规则。
例如:当一个方法调用另一个方法时,如果这两个方法都涉及事务操作,事务的传播行为定义了如何处理这些嵌套的事物,以及事务如何在方法调用之间传播和管理。

备注:事务:在计算机语言中指访问并可能更新数据库中数据项的一个程序执行单元。

常见的事物传播行为

对事务的要求程度可以从大到小排序:mandatory / supports / required / requires_new / nested / not supported / never

mandatory

要求当前存在事务,否则抛出异常。该传播特性适用于必须在事务中执行的方法,如果没有事务存在,则会抛出异常。

supports

如果当前存在事务,则加入该事务,如果没有事务,则以非事务方式执行。该传播特性适用于不要求事务支持的方法,它会根据当前的事务上下文决定是否执行事务。

required

如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。(required需要,没有新建,有则加入)。

required_new

创建新事务,无论当前存不存在事务,都创建新事务。(requires_new需要新的,不管有没有,直接创建新事务)

nested

如果当前存在事务,则在嵌套事务中执行。如果没有事务,则创建一个新的事务。嵌套事务是当前事务的一部分,可以回滚独立于主事务的操作。如果主事务回滚,嵌套事务也会回滚;如果嵌套事务回滚,主事务可以选择回滚或继续执行。

not support

以非事务方式执行方法,如果当前存在事务,则将其挂起。该传播特性适用于不希望方法在事务中执行的情况,它会暂停当前事务,以非事务方式执行方法。

never

要求当前不存在事务,否则抛出异常。该传播特性适用于必须在非事务方式下执行的方法,如果当前存在事务,则会抛出异常。

三、为什么要有事务的传播行为,它是为了解决什么问题?

事务的传播行为,是为了解决多个方法调用中涉及到事务管理的问题,通过定义事务的传播行为,可以控制事务在不同方法之间的行为方式。
解决了多个方法之间事务管理、嵌套事务、隔离性和一致性等问题。

四、如何使用事务的传播行为

目前以spring框架举例,举例spring支持的事务。通过使用@Transactional注解实现。

外围方法没有事务,内围方法有事务。

  1. 添加@Transactional注解的两个业务层方法
@Transactional(propagation = Propagation.REQUIRED )
    @Override
    public List<CourseContentEntity> queryCourseContent(CourseContentEntity courseContent) {
        return courseContentMapper.queryCourseContentRecord(courseContent);
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public List<CourseContentEntity> queryCourseContentByCreateList(List<String> createByList) {
        return courseContentMapper.queryCourseContentByCreateList(createByList);
    }
  1. 测试代码
@Test
	void contextLoads() {
		CourseContentEntity courseContent=new CourseContentEntity();
		courseContent.setCreatedBy("张三");
		
		courseContentService.queryCourseContent(courseContent);
		List<String> createNames=new ArrayList<>();
		createNames.add("张三");
		createNames.add("李四");
		createNames.add("王五");
		courseContentService.queryCourseContentByCreateList(createNames);
		throw new RuntimeException();
	}
  1. 结果
    通过下面图片可以看到,queryCourseContent方法和queryCourseContentByCreateList方法都成功执行了。当前外围的异常管不着内围的方法。
    案例挑战——事务传播行为-LMLPHP

外围方法有事务,内围方法有事务。

  1. 添加@Transactional注解的两个业务层方法
@Transactional(propagation = Propagation.REQUIRED )
    @Override
    public List<CourseContentEntity> queryCourseContent(CourseContentEntity courseContent) {
        return courseContentMapper.queryCourseContentRecord(courseContent);
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public List<CourseContentEntity> queryCourseContentByCreateList(List<String> createByList) {
        return courseContentMapper.queryCourseContentByCreateList(createByList);
    }
  1. 测试方法
@Transactional(propagation = Propagation.REQUIRED)
	@Test
	void contextLoads() {
		CourseContentEntity courseContent=new CourseContentEntity();
		courseContent.setCreatedBy("张三");

		courseContentService.queryCourseContent(courseContent);
		List<String> createNames=new ArrayList<>();
		createNames.add("张三");
		createNames.add("李四");
		createNames.add("王五");
		courseContentService.queryCourseContentByCreateList(createNames);
		throw new RuntimeException();
	}

结果:通过下方图片可以看到并没有像上次打印出执行的sql语句来,
内围方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
案例挑战——事务传播行为-LMLPHP

备注:其他类型的事务传播行为,可以按照上方的测试的方式进行验证。

五、总结

  1. 通过对于上方事务各种传播行为的认识和实践之后,在具体的项目中相对于之前,更加能够进行灵活应用。
  2. 后续会对本地事物和分布式事物进行认知和实践将经历转换为自己的经验。

六、升华

1.针对于spring的@Transactional的实现原理(动态代理)之后需要进行学习和实践。

  1. 通过5w2h的方法,能够从不同维度去认知任何事物。将其进行刻意练习,成为高效学习的习惯。
07-06 07:27