面试官:问你一个,Spring事务是如何传播的?( 七 )
流程和提交是一样的 , 先是判断有没有回滚点 , 如果有就回到到回滚点并清除该回滚点;如果没有则判断是不是新事务(PROPAGATION_REQUIRED属性下的最外层事务和PROPAGATION_REQUIRES_NEW属性下的事务) , 满足则直接回滚当前事务 。 回滚完成后同样需要清除掉当前的事务状态并恢复挂起的连接 。 另外需要特别注意的是在catch里面调用完回滚逻辑后 , 还通过throw抛出了异常 , 这意味着什么?意味着即使是嵌套事务 , 内层事务的回滚也会导致外层事务的回滚 , 也就是addA的事务也会跟着回滚 。 至此 , 事务的传播原理分析完毕 , 深入看每个方法的实现是很复杂的 , 但如果仅仅是分析各个传播属性对事务的影响 , 则有一个简单的方法 。 我们可以将内层事务切面等效替换掉invocation.proceedWithInvocation方法 , 比如上面两个类的调用可以看作是下面这样:
// addA的事务TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try { // addB的事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try {retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex; } finally {cleanupTransactionInfo(txInfo); } //事务提交 commitTransactionAfterReturning(txInfo);}catch (Throwable ex) { //事务回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex;}//事务提交commitTransactionAfterReturning(txInfo);
这样看是不是很容易就能分析出事务之间的影响以及是提交还是回滚了?下面来看几个实例分析 。
实例分析我再添加一个C类 , 和addC的方法 , 然后在addA里面调用这个方法 。
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try { // addB的事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try {b.addB(); } catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex; } //事务提交 commitTransactionAfterReturning(txInfo); // addC的事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try {c.addC(); } catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex; } //事务提交 commitTransactionAfterReturning(txInfo);}catch (Throwable ex) { //事务回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex;}//事务提交commitTransactionAfterReturning(txInfo);
等效替换后就是上面这个代码 , 我们分别来分析 。
- 都是PROPAGATION_REQUIRED属性:通过上面的分析 , 我们知道三个方法都是同一个连接和事务 , 那么任何一个出现异常则都会回滚 。
- addB为PROPAGATION_REQUIRES_NEW:如果B中抛出异常 , 那么B中肯定会回滚 , 接着异常向上抛 , 导致A事务整体回滚;如果C中抛出异常 , 不难看出C和A都会回滚 , 但B已经提交了 , 因此不会受影响 。
- addC为PROPAGATION_NESTED , addB为PROPAGATION_REQUIRES_NEW:如果B中抛出异常 , 那么B回滚并抛出异常 , A也回滚 , C不会执行;如果C中抛出异常 , 先是回滚到回滚点并抛出异常 , 所以A也回滚 , 但B此时已经提交 , 不受影响 。
推荐阅读
- 微软Edge迎来一个新的浮层菜单 用于管理下载进度
- 一个亮点解读 创维小湃P3 Pro必须要买的理由
- 华为认证HCIP-GaussDB-OLTP发布,下一个高级DBA会是你吗
- 又黄一个APP,“品牌收购机”成“没落收割机”,收一黄一
- 教你用Siri来控制电脑:真香
- Google AI建立了一个能够分析烘焙食谱的机器学习模型
- 虾米音乐宣布2月5日关停 人们更关心谁将是下一个
- 虾米音乐一个月后关停 我的听歌记录和个人信息怎么办?
- 华为隐藏一个会议神器,一分钟录入1000字,打字慢的可以看看
- 荣耀手环6简评:这是一个有“偏见”的产品