Spring事务传播性

是什么

在这里插入图片描述
当多个含有事务的方法进行嵌套调用时,多个方法处理事务的规则

传播行为

PROCPAGATION_REQUIRED

理论

  • 如果外层方法开启了事务,内层方法就会加入到外层事务
  • 如果外层方法未开启事务,内层方法就会开启新的事务

可保证多个嵌套的事务方法在同一个事务内执行,也就是保证多个事务方法同时提交、同时回滚,这个机制可以满足大多数业务场景。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

B方法传播性是REQUIRED,所以methodB会合并到methodA开启的事务中执行,当B方法出异常并回滚后,A方法操作也会回滚。

问:如果B方法中的异常使用try catch捕获后,A方法还回回滚么?
会回滚,因为REQUIRED传播性的语义就是嵌套调用的多个事务方法在同一个事务内执行,而事务本身是有原子性的,有一个事务方法抛出异常回滚了,那么所有的方法都会回滚。

PROCPAGATION_REQUIRED_NEW

理论

每次都开启新的事务,如果外层调用方已经开启了事务,就先把外层事务挂起,执行新事务,执行完毕后再恢复上层事务的执行。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED_NEW)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

执行流程图:
在这里插入图片描述
由于A方法与B方法未在一个事务中执行,当B方法出现异常并回滚后,方法A的入库操作不受影响。

PROCPAGATION_SUPPORTE

理论

  • 如果外层方开启了事务,那么当前方法就加入到外层事务
  • 如果外层方未开启事务,那么当前方法也不会创建新事务

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.SUPPORTE)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

如果方法A本身开启了事务(传播性为REQUIRED),那么方法B会加入方法A的事务中。
如果方法A未开启事务,那么方法B也不会开启事务,在无事务的情况下执行。

PROCPAGATION_SUPPORTED

理论

不支持事务,如果外层方法开启了事务,那么当前方法以非事务的方式执行当前方法逻辑,执行完毕后,再恢复外层事务的执行。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.NOT_SUPPORTED)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

执行流程图:
在这里插入图片描述

PROCPAGATION_NEVER

不支持事务,如果外层方法开启了事务,当前方法会抛出异常。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.NEVER)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

方法A调用方法B时,由于方法B的传播性为NEVER,B方法会抛出异常。

PROCPAGATION_MANDATORY

理论

配置了该传播性的方法只能在已经存在事务的方法中被调用,否则会抛出异常。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		serviceB.methodB();
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.NEVER)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

方法A未开启事务,调用了方法B时,会报异常。

PROCPAGATION_NESTED

理论

嵌套调用

  • 当外层调用方存在事务,当前方法会合并到外层事务
  • 当外层调用方不存在事务,当前方法会开启事务
    该传播性与REQUIRED传播性一致,不同点是,该传播行为可以保存状态保存点,当事务回滚时,可以回滚到某一个保存点上,避免所有的事务都回滚。

实例

@Service
public class ServiceA {
	@Autowired
	private SerivceB serbiceB;

	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.REQUIRED)
	public void methodA() {
		//1.1 A方法入库操作
		insert();
		Systome.out.println("insert something to db");
		//1.2 调用B方法入库
		try {
			serviceB.methodB();
		} catch(Exception e){
		}
		//1.3  执行更新操作
		udpate();	
	}
}

@Serivce
public class ServiceB {
	
	@Transactional(rollbackFor = Exception.class, propagation = Porpagation.NESTED)
	public void methodB() {
		insert();
		Systome.out.println("insert something to db");
		//抛出异常
		//throw new RuntiomeException();
	}
}

使用该传播性,会建立保存点。
当方法B的异常被捕获时,方法B的事务会回滚,而1.1和1.3操作都会被提交。

总结

在日常的开发中,我们常用的传播性有两种,REQUIRED和REQUIRED_NEW。

  • REQUIRED适用于应用层编排不同业务域的服务实现同一个功能时,将每个方法都设置为REQUIRED,从而保证不同业务域的方法同时提交变动或者同时回滚。
  • REQUIRED_NEW可以保证内层方法开启独立于外层方法的事务,如果内层事务方法抛出了异常,并且外层事务方法catch住了异常,并没有向外抛出,则外层事务不会回滚。如果内层事务抛出异常,并且外层事务方法没有catch掉异常,则外层事务也会回滚。适用于内层方法的执行独立于外层方法的场景,例如日志插入。
  • NEVER使用场景:事务方法A内调用了非事务方法B,方法B内部作用是rpc调用远程方法,假设事务A方法开启了事务,默认情况下非事务方法B会合并到方法A的事务内执行。而我们知道像rpc这种耗时比较长的调用,实践上是不建议放到事务内执行的,因为这会导致开启的事务长期得不到释放,可能会导致数据库连接池被打满。而假设方法B上加了Never方法,则显示告诉上层调用者,不要在开启事务后调用自己。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值