Spring Boot事务:理解事务的传播

在我之前的教程中,Spring Boot事务管理例子中,我们了解了事务的声明式实现和管理。在这片文章中,我们会
来看事务的传播性以及不同的传播类型。下一篇文章中,我们将会学习Spring Boot 事务回滚Spring Boot事务隔离级别

事务的传播性是什么?

任何应用程序都涉及许多服务或组件,这些服务或组件需要调用其他服务或组件。事务传播指示任何组件或服务是否会参与或将参与事务,以及__如果调用组件/服务已经创建或尚未创建事务,它将如何执行__。

在这里插入图片描述

准备开始

我们将利用上一章已经开发好的Spring Boot事务项目。它已经具有Organization Service,该服务调用了Employee ServiceHealth Insurance Service

并且,在之前的例子中,我们只是在Organization Service上添加了事务注解
但是,假设用户希望同时调用Employee Service,即:

客户端通过Organization Service来调用Employee Service

在这里插入图片描述
客户端直接调用Employee Service

在这里插入图片描述
因为可以直接调用Employee Service,我们将对Employee Service使用事务注解。所以,Employee ServiceOrganization Service都将使用事务注解。

我们将通过观察Employee ServiceOrganization Service的行为来观察各种传播场景。有六种类型的事务传播:

  • REQUIRED
  • SUPPORTS
  • NOT_SUPPORTED
  • REQUIRES_NEW
  • NEVER
  • MANDATORY

事务传播,默认是REQUIRED

在这里插入图片描述
左侧:如果insertEmployee()方法被直接调用,它会自己创建一个自己的新的事务。

右侧:如果insertEmployee()方法是从另外一个服务中调用的;

  • 如果调用的service已经有一个事务,那么该方法就会使用已经存在的事务
  • 如果调用的service中不存在事务,那么方法就会创建一个新的事务
    所以如果存在事务,那么insertEmployee()方法就会继续使用原有的事务,否则就会利用REQUIRED来创建一个新的事务。

在这里,Organization ServiceEmployee Service都定义了事务的传播行为为Required这也是默认的事务传播行为,

代码

下面是Organization Service的代码:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
	
	@Autowired
	EmployeeService employeeService;
	
	@Autowired
	HealthInsuranceService healthInsuranceService;
	
	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

Employee Service的代码如下所示:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {
	
	@Autowired
	EmployeeDao employeeDao;
	
	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}
	
	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

__通过使用OrganizationService__调用EmployeeService:

在这里插入图片描述

直接调用employeeService

在这里插入图片描述

事务传播行为-SUPPORTS

在这里插入图片描述
从上图可以看出来两点

  • EmployeeService中方法insertEmployee()被直接调用的话,如果使用的事务传播行为为SUPPORTS,那么它不会自己创建自己新的事务
  • EmployeeServiceinsertEmployee()通过OrganizationService调用的时候,如果OrganizationService存在事务,那么insertEmployee就会沿用OrganizationService的事务传播行为,
    否则如果OrganizationService不存在事务传播行为,那么insertEmployee()方法就会执行,但是不会开启任何事务。

在上面的示例中,OrganizationService的事务传播行为定义为REQUIRED,EmployeeService的事务定义为SUPPORTS

代码

OrganizationService的实现如下:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;

	@Autowired
	HealthInsuranceService healthInsuranceService;

	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
		throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

Employee Service的代码如下所示:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.SUPPORTS)
public class EmployeeServiceImpl implements EmployeeService {
	
	@Autowired
	EmployeeDao employeeDao;
	
	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}
	
	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

在这里插入图片描述

事务传播行为:NOT_SUPPORTED

[外链图片转存失败(img-CpzTju2a-1566307900626)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_009.png)]

从上面的描述中可以知道,当EmployeeServiceinsertEmployee被设定事务传播行为为NOT_SUPPORTED的时候, 直接调用该方法或者通过OrganizationService调用,该方法都不会创建事务或者沿用OrganizationService`的事务。

代码

OrganizationService的实现如下:`

 package com.javainuse.service.impl;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;
	
	@Autowired
	HealthInsuranceService healthInsuranceService;
	
	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

EmployeeService的实现:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;
	
	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}
	
	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

在这里插入图片描述

事务的传播行为REQUIRES_NEW

[外链图片转存失败(img-scz5W9d9-1566307900629)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_011.png)]

从图中的描述中可以知道,无论是直接被调用还是通过其他的Service来调用,事务的传播行为REQUIRES_NEW总是会创建自己的事务。

代码

OrganizationService的实现如下:`

 package com.javainuse.service.impl;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
	
	@Autowired
	EmployeeService employeeService;
	
	@Autowired
	HealthInsuranceService healthInsuranceService;
	
	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

EmployeeService的实现:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.REQUIRES_NEW)
public class EmployeeServiceImpl implements EmployeeService {
	
	@Autowired
	EmployeeDao employeeDao;
	
	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}
	
	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

[外链图片转存失败(img-JY3oHdqE-1566307900630)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_012.png)]

[外链图片转存失败(img-1slkp2R0-1566307900631)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_013.png)]

事务的传播行为:NEVER

[外链图片转存失败(img-RmJGIdHY-1566307900632)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_014.png)]

从上图可以知道,如果该方法直接被调用,它不会自己创建一个事务;如果该方法被其它的进行调用,如果调用的Service方法存在事务,那么就会抛出一个异常。
否则,它不会创建事务,然后自己运行。

代码

OrganizationService的实现如下:`

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {

	@Autowired
	EmployeeService employeeService;
	
	@Autowired
	HealthInsuranceService healthInsuranceService;
	
	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

EmployeeService实现:

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.NEVER)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

[外链图片转存失败(img-XwOPQdEb-1566307900633)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_015.png)]

事务的传播行为:MANDATORY

[外链图片转存失败(img-SNTbbJul-1566307900634)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_016.png)]

如果方法上指定的事务传播行为为MANDATORY,直接被调用的时候会抛出异常;如果被其它服务调用,存在事务传播行为就会沿用,否则就会抛出异常。

代码

OrganizationService的实现如下:`

package com.javainuse.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;

@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
	
	@Autowired
	EmployeeService employeeService;
	
	@Autowired
	HealthInsuranceService healthInsuranceService;
	
	@Override
	public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.insertEmployee(employee);
		
		if (employee.getEmpId().equals("emp1")) {
			throw new RuntimeException("thowing exception to test transaction rollback");
		}
		
		healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
	}
	
	@Override
	public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
		employeeService.deleteEmployeeById(employee.getEmpId());
		healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
	}
}

EmployeeService实现:

 package com.javainuse.service.impl;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
@Transactional(propagation=Propagation.MANDATORY)
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;
	
	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}
	
	@Override
	public void deleteEmployeeById(String empid) {
		employeeDao.deleteEmployeeById(empid);
	}
}

输出

[外链图片转存失败(img-zfBk8eDD-1566307900635)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_017.png)]

事务传播行为总结

  • REQUIRED :一直在事务中执行,如果这里存在事务,它会使用已经存在的事务;如果不存在事务,它会新建一个事务。
  • SUPPORTS: 它可能在事务中运行,也可能不在事务中运行。如果当前事务存在,则支持它。如果不存在,则在没有事务的情况下执行。
  • NOT_SUPPORTED : 始终在没有事务的情况下执行。如果存在现有事务,则挂起该事务。
  • REQUIRES_NEW : 始终在新事务中执行。如果存在现有事务,则挂起该事务。
  • NEVER : 在没有任何事务的情况下执行。如果存在现有事务,则引发异常
  • MANDATORY :始终在事务中执行。如果存在现有事务,则使用该事务。如果没有现有事务,它将引发异常。

原文链接:https://dzone.com/articles/spring-boot-transactions-tutorial-understanding-tr
作者:Rida Shaikh
译者:lee

发布了453 篇原创文章 · 获赞 539 · 访问量 156万+

猜你喜欢

转载自blog.csdn.net/u012934325/article/details/99887077
今日推荐