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注冊了一個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是個抽象類,聲明實現(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() {
}注意這里注釋說明了異常不會被捕獲,而且建議不在這里拋出TransactionException的子類;另外對于afterCommit有數(shù)據(jù)庫相關(guān)操作的建議使用PROPAGATION_REQUIRES_NEW這個事務(wù)傳播級別,不然afterCommit的操作可能不會生效
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方法會把TransactionSynchronization注冊到當(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(),注意這里沒有try catch,說明triggerAfterCommit的異常最終會拋給調(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方法,如果其中有一個有異常拋出則中斷
小結(jié)
使用TransactionSynchronizationManager.registerSynchronization可以在當(dāng)前線程的事務(wù)注冊一個TransactionSynchronizationAdapter,可以在afterCommit方法也就是事務(wù)提交成功之后執(zhí)行一些額外邏輯;注意這里拋出的異常不影響事務(wù)提交,但是異常不會被catch需要由調(diào)用方處理,對于afterCommit有數(shù)據(jù)庫相關(guān)操作的建議使用PROPAGATION_REQUIRES_NEW這個事務(wù)傳播級別,不然afterCommit的db操作可能不會生效。
在事務(wù)提交之后做一些事情可能不需要TransactionSynchronizationManager.registerSynchronization這種方式也能實現(xiàn),也就是需要額外一層來調(diào)用事務(wù)操作,有異常會拋出,沒有異常則執(zhí)行事務(wù)提交之后的事情,前提就是事務(wù)回滾異常不能被吞掉,不然外層調(diào)用可能以為事務(wù)成功了還有一種方式就是使用TransactionalEventListener,這種方式比TransactionSynchronizationManager.registerSynchronization更為優(yōu)雅一些
doc
以上就是spring的TransactionSynchronizationAdapter事務(wù)源碼解析的詳細(xì)內(nèi)容,更多關(guān)于spring TransactionSynchronizationAdapter的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java Web學(xué)習(xí)教程之Hibernate And MyBatis的理解
這篇文章主要給大家介紹了關(guān)于Java Web學(xué)習(xí)教程之Hibernate And MyBatis的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04
解析ConcurrentHashMap: 紅黑樹的代理類(TreeBin)
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧2021-06-06
SpringBoot利用validation實現(xiàn)優(yōu)雅的校驗參數(shù)
數(shù)據(jù)的校驗是交互式網(wǎng)站一個不可或缺的功能,如果數(shù)據(jù)庫中出現(xiàn)一個非法的郵箱格式,會讓運(yùn)維人員頭疼不已。本文將介紹如何利用validation來對數(shù)據(jù)進(jìn)行校驗,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-06-06
詳解Idea 2019.2 安裝lombok插件失效問題解決
這篇文章主要介紹了詳解Idea 2019.2 安裝lombok插件失效問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Java如何使用while循環(huán)計算一個整數(shù)的位數(shù)
這篇文章主要介紹了Java使用while循環(huán)計算一個整數(shù)的位數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

