如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点呢?
在当前含有事务方法内部调用其他的方法(无论该方法是否含有事务),这就属于Spring事务传播机制的知识点范畴了。
Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:
1.基于接口代理(JDK代理)基于接口代理
2.基于CGLib代理(子类代理)基于子类代理
下面列举几个事务的例子可以看下是否生效:
// Service方法
@Transactional
public Employee addEmployee() throws RuntimeException {
Employee employee = new Employee("3y", 23);
employeeRepository.save(employee);
// 假设这里出了Exception
int i = 1 / 0;
return employee;
}
// Controller调用
@RequestMapping("/add")
public Employee addEmployee() {
Employee employee = null;
try {
employee = employeeService.addEmployee();
} catch (RuntimeException e) {
e.printStackTrace();
}
return employee;
}
事务可以生效,Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类),Error进行回滚。此处属于运行时异常,因此可以回滚事务。
// @Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void updateOrder(Order order) {
try {
// update order
} catch {
throw new Exception("更新错误");
}
}
}
这样事务也是不生效的,如果你想触发其他异常的回滚,需要在注解上配置一下,如,可以通过配置@Transactional(rollbackFor = Exception.class)
自定义其他回滚类型。
此处贴一张异常继承图:
嵌套事务情况:
1、
// 没有事务的方法去调用有事务的方法
public Employee addEmployee2Controller() throws RuntimeException {
return this.addEmployee();
}
@Transactional
public Employee addEmployee() throws RuntimeException {
employeeRepository.deleteAll();
Employee employee = new Employee("3y", 23);
// 模拟异常
int i = 1 / 0;
return employee;
}
2、
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void update(Order order) {
updateOrder(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrder(Order order) {
// update order
}
}
Spring事务管理用的是AOP,AOP底层用的是动态代理。所以如果我们在类或者方法上标注注解@Transactional,那么会生成一个代理对象。
显然地,我们拿到的是代理(Proxy)对象,调用addEmployee2Controller()方法,而addEmployee2Controller()方法的逻辑是target.addEmployee(),调用回原始对象(target)的addEmployee()。所以这次的调用压根就没有事务存在,更谈不上说Spring事务传播机制了。以上两种因为它们发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,被调用的都不支持事务。从其他类中调用时是可以生效的,下边这种情况是可以生效的:
@Service
public class TestService {
@Autowired
private EmployeeRepository employeeRepository;
@Transactional
public Employee addEmployee() throws Exception {
employeeRepository.deleteAll();
Employee employee = new Employee("3y", 23);
// 模拟异常
int i = 1 / 0;
return employee;
}
}
@Service
public class EmployeeService {
@Autowired
private TestService testService;
// 没有事务的方法去调用别的类有事务的方法
public Employee addEmployee2Controller() throws Exception {
return testService.addEmployee();
}
}
所以,嵌套事务情况需要停下思考下事务是否生效。事务在业务和技术中还是很重要的,要是生产出现这种问题,直接卷铺盖走人了。