@Transactional注解真的有必要聲明rollbackFor屬性嗎?

@Transactional注解真的有必要聲明rollbackFor屬性嗎??今天在看spring的事務底層源碼時,想到一個問題,@Transactional注解真的有必要聲明rollbackFor屬性嗎?因為之前有許多資料,包括公司的java編碼規范上也有提及到這一點 。
?不知道讀者們有沒想過這個問題,但我看完源碼后,個人覺得是沒必要的 。見解不到位的話,希望讀者能指明 。
異常:如下圖所示,我們都知道Exception分為運行時異常RuntimeException和非運行時異常(檢查時異常) 。

@Transactional注解真的有必要聲明rollbackFor屬性嗎?

文章插圖
那么spring默認會對如上的哪些異常進行回滾呢?
答案:RuntimeException、Error.
spring源碼如下說明:?spring在執行方法拋出異常后 , 會調用completeTransactionAfterThrowing方法,也在該方法中會去判斷并執行是回滾還是提交操作 。
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.getTransactionStatus() != null) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +"] after exception: " + ex);}// transactionAttribute的實現類為RuleBasedTransactionAttribute,父類為DefaultTransactionAttributeif (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {try {txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by rollback exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException | Error ex2) {logger.error("Application exception overridden by rollback exception", ex);throw ex2;}}else {// We don't roll back on this exception.// Will still roll back if TransactionStatus.isRollbackOnly() is true.try {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by commit exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException | Error ex2) {logger.error("Application exception overridden by commit exception", ex);throw ex2;}}}我們看到這個if分支進行分析,如果該if滿足,則會進行回滾 。
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex))查看txInfo.transactionAttribute.rollbackOn(ex)方法,其中的this.rollbackRules就是我們在@Transactional注解上配置的rollbackFor屬性 , 
public boolean rollbackOn(Throwable ex) {RollbackRuleAttribute winner = null;int deepest = Integer.MAX_VALUE;if (this.rollbackRules != null) {// 遍歷所有的RollbackRuleAttribute , 判斷現在拋出的異常ex是否匹配RollbackRuleAttribute中指定的異常類型的子類或本身for (RollbackRuleAttribute rule : this.rollbackRules) {int depth = rule.getDepth(ex);if (depth >= 0 && depth < deepest) {deepest = depth;winner = rule;}}}// User superclass behavior (rollback on unchecked) if no rule matches.if (winner == null) {return super.rollbackOn(ex);}// ex所匹配的RollbackRuleAttribute,可能是NoRollbackRuleAttribute,如果是匹配的NoRollbackRuleAttribute,那就表示現在這個異常ex不用回滾return !(winner instanceof NoRollbackRuleAttribute);}我這里簡單配了個ServiceException 。如下圖
@Transactional注解真的有必要聲明rollbackFor屬性嗎?

文章插圖
根據一:在rollbackFor屬性元素遍歷時,會根據getDepth方法去找拋出的異常 , 是不是就是我們聲明的rollbackFor屬性中的異常,如果是,判斷是不是NoRollbackRuleAttribute類型,是的話就不回滾,否則就回滾 。
再看getDepth方法,會根據拋出的異常 , 判斷異常名字是否跟我們聲明的異常是否相同,相同則返回,不同則遞歸拋出異常的父類,直到遍歷到Throwable.class頂類 。
private int getDepth(Class<?> exceptionClass, int depth) {if (exceptionClass.getName().contains(this.exceptionName)) {// Found it!return depth;}// If we've gone as far as we can go and haven't found it...if (exceptionClass == Throwable.class) {return -1;}return getDepth(exceptionClass.getSuperclass(), depth + 1);}根據二:如果getDepth找不到對應的異常類,就從默認實現類DefaultTransactionAttribute.rollbackOn(Throwalbe x)方法進行判斷 。
@Overridepublic boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);}DefaultTransactionAttribute

推薦閱讀