spring的TransactionSynchronizationAdapter事務(wù)源碼解析
序
本文主要研究一下spring的TransactionSynchronizationAdapter
示例代碼
public void insert(TechBook techBook){ bookMapper.insert(techBook); // send after tx commit but is async TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { System.out.println("send email after transaction commit..."); } } ); System.out.println("service end"); }
使用TransactionSynchronizationManager.registerSynchronization注冊(cè)了一個(gè)TransactionSynchronizationAdapter,在其afterCommit方法也就是事務(wù)提交成功之后執(zhí)行一些額外邏輯
TransactionSynchronizationAdapter
org/springframework/transaction/support/TransactionSynchronizationAdapter.java
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered { @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } @Override public void suspend() { } @Override public void resume() { } @Override public void flush() { } @Override public void beforeCommit(boolean readOnly) { } @Override public void beforeCompletion() { } @Override public void afterCommit() { } @Override public void afterCompletion(int status) { } }
TransactionSynchronizationAdapter是個(gè)抽象類,聲明實(shí)現(xiàn)TransactionSynchronization及Ordered接口
TransactionSynchronization
org/springframework/transaction/support/TransactionSynchronization.java
/** * Invoked after transaction commit. Can perform further operations right * <i>after</i> the main transaction has <i>successfully</i> committed. * <p>Can e.g. commit further operations that are supposed to follow on a successful * commit of the main transaction, like confirmation messages or emails. * <p><b>NOTE:</b> The transaction will have been committed already, but the * transactional resources might still be active and accessible. As a consequence, * any data access code triggered at this point will still "participate" in the * original transaction, allowing to perform some cleanup (with no commit following * anymore!), unless it explicitly declares that it needs to run in a separate * transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any * transactional operation that is called from here.</b> * @throws RuntimeException in case of errors; will be <b>propagated to the caller</b> * (note: do not throw TransactionException subclasses here!) */ default void afterCommit() { }
注意這里注釋說(shuō)明了異常不會(huì)被捕獲,而且建議不在這里拋出TransactionException的子類;另外對(duì)于afterCommit有數(shù)據(jù)庫(kù)相關(guān)操作的建議使用PROPAGATION_REQUIRES_NEW這個(gè)事務(wù)傳播級(jí)別,不然afterCommit的操作可能不會(huì)生效
registerSynchronization
org/springframework/transaction/support/TransactionSynchronizationManager.java
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations"); /** * Register a new transaction synchronization for the current thread. * Typically called by resource management code. * <p>Note that synchronizations can implement the * {@link org.springframework.core.Ordered} interface. * They will be executed in an order according to their order value (if any). * @param synchronization the synchronization object to register * @throws IllegalStateException if transaction synchronization is not active * @see org.springframework.core.Ordered */ public static void registerSynchronization(TransactionSynchronization synchronization) throws IllegalStateException { Assert.notNull(synchronization, "TransactionSynchronization must not be null"); Set<TransactionSynchronization> synchs = synchronizations.get(); if (synchs == null) { throw new IllegalStateException("Transaction synchronization is not active"); } synchs.add(synchronization); }
TransactionSynchronizationManager的registerSynchronization方法會(huì)把TransactionSynchronization注冊(cè)到當(dāng)前線程的synchronizations
processCommit
org/springframework/transaction/support/AbstractPlatformTransactionManager.java
private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try { boolean unexpectedRollback = false; prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); } unexpectedRollback = status.isGlobalRollbackOnly(); status.releaseHeldSavepoint(); } else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction commit"); } unexpectedRollback = status.isGlobalRollbackOnly(); doCommit(status); } else if (isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = status.isGlobalRollbackOnly(); } // Throw UnexpectedRollbackException if we have a global rollback-only // marker but still didn't get a corresponding exception from commit. if (unexpectedRollback) { throw new UnexpectedRollbackException( "Transaction silently rolled back because it has been marked as rollback-only"); } } catch (UnexpectedRollbackException ex) { // can only be caused by doCommit triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); throw ex; } catch (TransactionException ex) { // can only be caused by doCommit if (isRollbackOnCommitFailure()) { doRollbackOnCommitException(status, ex); } else { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); } throw ex; } catch (RuntimeException | Error ex) { if (!beforeCompletionInvoked) { triggerBeforeCompletion(status); } doRollbackOnCommitException(status, ex); throw ex; } // Trigger afterCommit callbacks, with an exception thrown there // propagated to callers but the transaction still considered as committed. try { triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } finally { cleanupAfterCompletion(status); } } private void triggerAfterCommit(DefaultTransactionStatus status) { if (status.isNewSynchronization()) { if (status.isDebug()) { logger.trace("Triggering afterCommit synchronization"); } TransactionSynchronizationUtils.triggerAfterCommit(); } }
AbstractPlatformTransactionManager的processCommit方法,在提交成功之后觸發(fā)triggerAfterCommit,這里調(diào)用了TransactionSynchronizationUtils.triggerAfterCommit(),注意這里沒(méi)有try catch,說(shuō)明triggerAfterCommit的異常最終會(huì)拋給調(diào)用方
triggerAfterCommit
org/springframework/transaction/support/TransactionSynchronizationUtils.java
public static void triggerAfterCommit() { invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations()); } public static void invokeAfterCommit(@Nullable List<TransactionSynchronization> synchronizations) { if (synchronizations != null) { for (TransactionSynchronization synchronization : synchronizations) { synchronization.afterCommit(); } } }
這里遍歷synchronizations執(zhí)行afterCommit方法,如果其中有一個(gè)有異常拋出則中斷
小結(jié)
使用TransactionSynchronizationManager.registerSynchronization可以在當(dāng)前線程的事務(wù)注冊(cè)一個(gè)TransactionSynchronizationAdapter,可以在afterCommit方法也就是事務(wù)提交成功之后執(zhí)行一些額外邏輯;注意這里拋出的異常不影響事務(wù)提交,但是異常不會(huì)被catch需要由調(diào)用方處理,對(duì)于afterCommit有數(shù)據(jù)庫(kù)相關(guān)操作的建議使用PROPAGATION_REQUIRES_NEW這個(gè)事務(wù)傳播級(jí)別,不然afterCommit的db操作可能不會(huì)生效。
在事務(wù)提交之后做一些事情可能不需要TransactionSynchronizationManager.registerSynchronization這種方式也能實(shí)現(xiàn),也就是需要額外一層來(lái)調(diào)用事務(wù)操作,有異常會(huì)拋出,沒(méi)有異常則執(zhí)行事務(wù)提交之后的事情,前提就是事務(wù)回滾異常不能被吞掉,不然外層調(diào)用可能以為事務(wù)成功了還有一種方式就是使用TransactionalEventListener,這種方式比TransactionSynchronizationManager.registerSynchronization更為優(yōu)雅一些
doc
以上就是spring的TransactionSynchronizationAdapter事務(wù)源碼解析的詳細(xì)內(nèi)容,更多關(guān)于spring TransactionSynchronizationAdapter的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java Web學(xué)習(xí)教程之Hibernate And MyBatis的理解
這篇文章主要給大家介紹了關(guān)于Java Web學(xué)習(xí)教程之Hibernate And MyBatis的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04解析ConcurrentHashMap: 紅黑樹(shù)的代理類(TreeBin)
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見(jiàn)問(wèn)題---ConcurrentHashMap知識(shí),一起看看吧2021-06-06java定時(shí)任務(wù)的實(shí)現(xiàn)方式
這篇文章主要介紹了java定時(shí)任務(wù)的實(shí)現(xiàn)方式,在應(yīng)用里經(jīng)常都有用到在后臺(tái)跑定時(shí)任務(wù)的需求,如何進(jìn)行java定時(shí)任務(wù),本文為大家進(jìn)行講解,感興趣的小伙伴們可以參考一下2016-02-02SpringBoot利用validation實(shí)現(xiàn)優(yōu)雅的校驗(yàn)參數(shù)
數(shù)據(jù)的校驗(yàn)是交互式網(wǎng)站一個(gè)不可或缺的功能,如果數(shù)據(jù)庫(kù)中出現(xiàn)一個(gè)非法的郵箱格式,會(huì)讓運(yùn)維人員頭疼不已。本文將介紹如何利用validation來(lái)對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-06-06詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決
這篇文章主要介紹了詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Java如何使用while循環(huán)計(jì)算一個(gè)整數(shù)的位數(shù)
這篇文章主要介紹了Java使用while循環(huán)計(jì)算一個(gè)整數(shù)的位數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01淺談Java多線程編程中Boolean常量的同步問(wèn)題
這篇文章主要介紹了淺談Java多線程編程中Boolean常量的同步問(wèn)題,主要針對(duì)線程之間同步了不同的布爾對(duì)象的問(wèn)題,需要的朋友可以參考下2015-10-10