Spring核心篇章:
Spring 5 中文解析核心篇-IoC容器之Bean作用域
Spring 5 中文解析核心篇-IoC容器之自定義Bean性質
Spring 5 中文解析核心篇-IoC容器之BeanDefinition繼承與容器拓展點
Spring 5 中文解析核心篇-IoC容器之基於註解的容器配置
Spring 5 中文解析核心篇-IoC容器之類路徑掃描和組件管理
Spring 5 中文解析核心篇-IoC容器之JSR330標準註解
Spring 5 中文解析核心篇-IoC容器之基於Java容器配置
Spring 5 中文解析核心篇-IoC容器之Environment抽象
Spring 5 中文解析核心篇-IoC容器之ApplicationContext與BeanFactory
Spring 5 中文解析核心篇-IoC容器之Resources
Spring 5 中文解析核心篇-IoC容器之數據校驗、數據綁定和類型轉換
Spring 5 中文解析核心篇-IoC容器之SpEL表達式
Spring 5 中文解析核心篇-IoC容器之AOP編程(上)")
Spring 5 中文解析核心篇-IoC容器之AOP編程(下)")
Spring 5 中文解析核心篇-IoC容器之Spring AOP API
Spring測試篇章:
Spring 5 中文解析核心篇-集成測試之概要和集成測試註解
Spring 5 中文解析核心篇-集成測試之TestContext(上)")
Spring 5 中文解析核心篇-集成測試之TestContext(中)")
Spring 5 中文解析測試篇-集成測試之TestContext(下)")
Spring 5 中文解析測試篇-Spring MVC測試框架
Spring 5 中文解析測試篇-WebTestClient
Spring存儲篇章:
Spring 5 中文解析數據存儲篇-Spring框架的事物支持模型的優勢
完整電子書地址
Spring框架通過使用以下兩種方式提供編程式事務管理的方法:
-
TransactionTemplate
或TransactionalOperator
-
TransactionManager
直接實現
Spring團隊通常建議對命令式流程中的編程式事務管理推薦使用TransactionTemplate
,對響應性代碼推薦TransactionalOperator
。第二種方法類似於使用JTA
UserTransaction
API,儘管異常處理的麻煩程度較小。
1.5.1 使用TransactionTemplate
TransactionTemplate
採用與其他Spring模板(如JdbcTemplate
)相同的方法。它使用一種回調方法(使應用程序代碼不必進行樣板獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。
如下面的示例所示,使用
TransactionTemplate
完全將你與Spring的事務基礎結構和api結合在一起。編程式事務管理是否適合你的開發需求是你必須自己做的決定。
必須在事務上下文中運行並且顯式使用TransactionTemplate
的應用程序代碼類似於下一個示例。作為應用程序開發人員,你可以編寫TransactionCallback
實現(通常表示為匿名內部類),其中包含你需要在事務上下文中運行的代碼。然後,你可以將自定義TransactionCallback
的實例傳遞給TransactionTemplate
上暴露的execute(..)
方法。以下示例顯示瞭如何執行此操作:
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method runs in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
如果沒有返回值,則可以將便捷的TransactionCallbackWithoutResult
類與匿名類一起使用,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回調中的代碼可以通過在提供的TransactionStatus
對象上調用setRollbackOnly()
方法來回滾事務,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
指定事物配置
你可以通過編程方式或配置方式在TransactionTemplate
上指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionTemplate
實例具有默認的事務設置。以下示例顯示了針對特定TransactionTemplate
的事務設置的編程自定義:
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}
以下示例通過使用Spring XML配置來定義帶有一些自定義事務設置的TransactionTemplate
:
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
然後,你可以將sharedTransactionTemplate
注入到所需的服務中。
最後,TransactionTemplate
類的實例是線程安全的,因為這些實例不維護任何對話狀態。但是,TransactionTemplate
實例確實會維護配置狀態。因此,儘管許多類可以共享一個TransactionTemplate
實例,但是如果一個類需要使用具有不同設置(例如,不同的隔離級別)的TransactionTemplate
,則需要創建兩個不同的TransactionTemplate
實例。
參考代碼:
org.liyong.dataaccess.starter.TransactionTemplateIocContainer
1.5.2 使用TransactionOperator
TransactionOperator
遵循類似於其他響應式操作符的設計。它使用一種回調方法(使應用程序代碼不必進行模版獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。
如以下示例所示,使用
TransactionOperator
絕對可以使你與Spring的事務基礎結構和API結合。編程式事務管理是否適合你的開發需求是你必須自己做的決定。
必須在事務上下文中運行並且顯式使用TransactionOperator
的應用程序代碼類似於下一個示例:
public class SimpleService implements Service {
// single TransactionOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;
// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionOperator = TransactionalOperator.create(transactionManager);
}
public Mono<Object> someServiceMethod() {
// the code in this method runs in a transactional context
Mono<Object> update = updateOperation1();
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}
TransactionalOperator
可以通過兩種方式使用:
- 使用
Reactor
類型的操作符樣式(mono.as(transactionalOperator :: transactional)
) - 其他所有情況的回調樣式(
transactionalOperator.execute(TransactionCallback <T>)
)
回調中的代碼可以通過在提供的ReactiveTransaction
對象上調用setRollbackOnly()
方法來回滾事務,如下所示:
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
取消信號
在響應式流中,Subscriber
可以取消其Subscription
並停止其Publisher
。Project Reactor
以及其他庫中的操作符,例如next()
、take(long)
、timeout(Duration)
等,都可以發出取消操作。沒有辦法知道取消的原因,無論是由於錯誤還是僅僅是出於進一步消費的興趣,並且在5.2版中,TransactionalOperator
默認在取消時提交事務。在版本5.3中,這種行為將發生改變,事務將在取消時回滾,以創建可靠的和確定性的結果。因此,重要的是要考慮從事務發佈服務器下游使用的操作符。特別是在Flux
或其他多值Publisher
的情況下,必須使用完整的輸出以允許事務完成。
指定事物配置
你可以為TransactionalOperator
指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionalOperator
實例具有默認的事務設置。以下示例顯示了針對特定TransactionalOperator
的事務設置的自定義:
public class SimpleService implements Service {
private final TransactionalOperator transactionalOperator;
public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// the transaction settings can be set here explicitly if so desired
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 seconds
// and so forth...
this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}
1.5.3 使用TransactionManager
以下各節說明命令式和響應式事務管理器的用法。
使用PlatformTransactionManager
對於命令式事務,可以直接使用org.springframework.transaction.PlatformTransactionManager
來管理事務。為此,通過bean引用將你使用的PlatformTransactionManager
的實現傳遞給bean。然後,通過使用TransactionDefinition
和TransactionStatus
對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// put your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
使用ReactiveTransactionManager
使用響應式事務時,可以直接使用org.springframework.transaction.ReactiveTransactionManager
來管理事務。為此,請通過bean引用將你使用的ReactiveTransactionManager
的實現傳遞給bean。然後,通過使用TransactionDefinition
和ReactiveTransaction
對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
reactiveTx.flatMap(status -> {
Mono<Object> tx = ...; // put your business logic here
return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});
Spring框架通過使用以下兩種方式提供編程式事務管理的方法:
-
TransactionTemplate
或TransactionalOperator
-
TransactionManager
直接實現
Spring團隊通常建議對命令式流程中的編程式事務管理推薦使用TransactionTemplate
,對響應性代碼推薦TransactionalOperator
。第二種方法類似於使用JTA
UserTransaction
API,儘管異常處理的麻煩程度較小。
1.5.1 使用TransactionTemplate
TransactionTemplate
採用與其他Spring模板(如JdbcTemplate
)相同的方法。它使用一種回調方法(使應用程序代碼不必進行樣板獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。
如下面的示例所示,使用
TransactionTemplate
完全將你與Spring的事務基礎結構和api結合在一起。編程式事務管理是否適合你的開發需求是你必須自己做的決定。
必須在事務上下文中運行並且顯式使用TransactionTemplate
的應用程序代碼類似於下一個示例。作為應用程序開發人員,你可以編寫TransactionCallback
實現(通常表示為匿名內部類),其中包含你需要在事務上下文中運行的代碼。然後,你可以將自定義TransactionCallback
的實例傳遞給TransactionTemplate
上暴露的execute(..)
方法。以下示例顯示瞭如何執行此操作:
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method runs in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
如果沒有返回值,則可以將便捷的TransactionCallbackWithoutResult
類與匿名類一起使用,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回調中的代碼可以通過在提供的TransactionStatus
對象上調用setRollbackOnly()
方法來回滾事務,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
指定事物配置
你可以通過編程方式或配置方式在TransactionTemplate
上指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionTemplate
實例具有默認的事務設置。以下示例顯示了針對特定TransactionTemplate
的事務設置的編程自定義:
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}
以下示例通過使用Spring XML配置來定義帶有一些自定義事務設置的TransactionTemplate
:
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
然後,你可以將sharedTransactionTemplate
注入到所需的服務中。
最後,TransactionTemplate
類的實例是線程安全的,因為這些實例不維護任何對話狀態。但是,TransactionTemplate
實例確實會維護配置狀態。因此,儘管許多類可以共享一個TransactionTemplate
實例,但是如果一個類需要使用具有不同設置(例如,不同的隔離級別)的TransactionTemplate
,則需要創建兩個不同的TransactionTemplate
實例。
參考代碼:
org.liyong.dataaccess.starter.TransactionTemplateIocContainer
1.5.2 使用TransactionOperator
TransactionOperator
遵循類似於其他響應式操作符的設計。它使用一種回調方法(使應用程序代碼不必進行模版獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。
如以下示例所示,使用
TransactionOperator
絕對可以使你與Spring的事務基礎結構和API結合。編程式事務管理是否適合你的開發需求是你必須自己做的決定。
必須在事務上下文中運行並且顯式使用TransactionOperator
的應用程序代碼類似於下一個示例:
public class SimpleService implements Service {
// single TransactionOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;
// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionOperator = TransactionalOperator.create(transactionManager);
}
public Mono<Object> someServiceMethod() {
// the code in this method runs in a transactional context
Mono<Object> update = updateOperation1();
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}
TransactionalOperator
可以通過兩種方式使用:
- 使用
Reactor
類型的操作符樣式(mono.as(transactionalOperator :: transactional)
) - 其他所有情況的回調樣式(
transactionalOperator.execute(TransactionCallback <T>)
)
回調中的代碼可以通過在提供的ReactiveTransaction
對象上調用setRollbackOnly()
方法來回滾事務,如下所示:
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
取消信號
在響應式流中,Subscriber
可以取消其Subscription
並停止其Publisher
。Project Reactor
以及其他庫中的操作符,例如next()
、take(long)
、timeout(Duration)
等,都可以發出取消操作。沒有辦法知道取消的原因,無論是由於錯誤還是僅僅是出於進一步消費的興趣,並且在5.2版中,TransactionalOperator
默認在取消時提交事務。在版本5.3中,這種行為將發生改變,事務將在取消時回滾,以創建可靠的和確定性的結果。因此,重要的是要考慮從事務發佈服務器下游使用的操作符。特別是在Flux
或其他多值Publisher
的情況下,必須使用完整的輸出以允許事務完成。
指定事物配置
你可以為TransactionalOperator
指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionalOperator
實例具有默認的事務設置。以下示例顯示了針對特定TransactionalOperator
的事務設置的自定義:
public class SimpleService implements Service {
private final TransactionalOperator transactionalOperator;
public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// the transaction settings can be set here explicitly if so desired
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 seconds
// and so forth...
this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}
1.5.3 使用TransactionManager
以下各節說明命令式和響應式事務管理器的用法。
使用PlatformTransactionManager
對於命令式事務,可以直接使用org.springframework.transaction.PlatformTransactionManager
來管理事務。為此,通過bean引用將你使用的PlatformTransactionManager
的實現傳遞給bean。然後,通過使用TransactionDefinition
和TransactionStatus
對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// put your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
使用ReactiveTransactionManager
使用響應式事務時,可以直接使用org.springframework.transaction.ReactiveTransactionManager
來管理事務。為此,請通過bean引用將你使用的ReactiveTransactionManager
的實現傳遞給bean。然後,通過使用TransactionDefinition
和ReactiveTransaction
對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
reactiveTx.flatMap(status -> {
Mono<Object> tx = ...; // put your business logic here
return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});
作者
個人從事金融行業,就職過易極付、思建科技、某網約車平臺等重慶一流技術團隊,目前就職於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分佈式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公眾號和博客站點對知識體系進行分享。關注公眾號:青年IT男 獲取最新技術文章推送!
博客地址: http://youngitman.tech
CSDN: https://blog.csdn.net/liyong1028826685
微信公眾號:
技術交流群: