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框架的事物支持模型的優勢
完整電子書地址
除了基於XML的聲明式方法進行事務配置外,還可以使用基於註解的方法。直接在Java源代碼中聲明事務語義會使聲明更加接近受影響的代碼。不存在過多耦合的風險,因為原本打算以事務方式使用的代碼幾乎總是以這種方式部署。
還支持使用標準的
javax.transaction.Transactional
註解來替代Spring自己的註解。請參閱JTA 1.2
文檔以獲取更多詳細信息。
使用@Transactional
註解提供的易用性將通過一個示例得到最好的說明,下面的示例對此進行了說明。考慮以下類定義:
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName) {
// ...
}
Foo getFoo(String fooName, String barName) {
// ...
}
void insertFoo(Foo foo) {
// ...
}
void updateFoo(Foo foo) {
// ...
}
}
在上面的類級別使用,註解表示聲明類(及其子類)的所有方法的默認值。另外,每種方法都可以單獨註解。注意,類級別的註解不適用於類層次結構中的祖先類。在這種情況下,需要在本地重新聲明方法,以參與子類級別的註解。
當將一個以上的POJO類在Spring上下文中定義為bean時,可以通過@Configuration
類中的@EnableTransactionManagement
註解使bean實例具有事務性。有關完整的詳細信息,請參見javadoc。
在XML配置中,<tx:annotation-driven/>
標籤提供了類似的便利操作:
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/><!-- a TransactionManager is still required --> //1
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>
- 使bean實例具有事務性的行為
如果要連接的
TransactionManager
的bean名稱具有名稱transactionManager
,則可以在<tx:annotation-driven/>
標籤中省略transaction-manager
屬性。如果要依賴注入的TransactionManager
bean具有其他名稱,則必須使用transaction-manager
屬性,如上例所示。
相對於命令式編程,響應式事務方法使用響應式返回類型,如下清單所示:
// the reactive service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Publisher<Foo> getFoo(String fooName) {
// ...
}
Mono<Foo> getFoo(String fooName, String barName) {
// ...
}
Mono<Void> insertFoo(Foo foo) {
// ...
}
Mono<Void> updateFoo(Foo foo) {
// ...
}
}
請注意,對於返回的Publisher
,在響應流取消信號方面有一些特殊注意事項。有關更多詳細信息,請參見“使用TransactionOperator
”下的“取消信號”部分。
方法可見性和@Transactional
使用代理時,應僅將
@Transactional
註解應用於具有公共可見性的方法。如果使用@Transactional
註解對protected
、private
或程序包可見的方法進行註解,則不會引發任何錯誤,但是帶註解的方法不會顯示已配置的事務設置。如果需要註解非公共方法,請考慮使用AspectJ
(稍後描述)。
你可以將@Transactional
註解應用於接口定義、接口上的方法、類定義或類上的公共方法。但是,僅@Transactional
註解的存在不足以激活事務行為。 @Transactional
註解僅僅是元數據,可以被某些支持@Transactional
的運行時基礎結構使用,並且可以使用元數據來配置具有事務行為的適當Bean。在前面的示例中,<tx:annotation-driven/>
元素打開事務行為。
Spring團隊推薦僅使用
@Transactional
註解對具體類(以及具體類的方法)進行註解,而不是對接口進行註解。你當然可以在接口(或接口方法)上放置@Transactional
註解,但這僅在你使用基於接口的代理時才可以達到預期。Java註解不能從接口繼承的事實意味著,如果你使用基於類的代理(proxy-target-class="true"
)或基於編織的切面(mode =“aspectj”
),則事務設置不會由代理和編織基礎結構識別,並且該對象未包裝在事務代理中。在代理模式(默認)下,僅攔截通過代理傳入的外部方法調用。這意味著即使調用的方法標記有
@Transactional
,自調用(實際上是目標對象中的方法調用目標對象的另一種方法)也不會在運行時使用實際事務(譯者:調用實例自身的方法就是自調用)。另外,必須完全初始化代理才能提供預期的行為,因此你不應在初始化代碼(即@PostConstruct
)中依賴此功能。
如果期望自調用也與事務包裝在一起,請考慮使用AspectJ
模式(請參見下表的mode
屬性)。在這種情況下,首先沒有代理。而是編織目標類(即,修改其字節碼)以將@Transactional
轉換為任何方法上的運行時行為。
XML屬性 | 註解屬性 | 默認值 | 描述 |
---|---|---|---|
transaction-manager |
N/A (查看 Transaction-ManagementConfigurer -javadoc) |
transactionManager |
要使用的事務管理器的名稱。如上例所示,僅當事務管理器的名稱不是transactionManager 時才需要。 |
mode |
mode |
proxy |
默認模式(代理)通過使用Spring的AOP框架來處理帶註解的bean(遵循代理語義,如前所述,僅適用於通過代理傳入的方法調用)。替代模式(aspectj )則將受影響的類與Spring的AspectJ 事務切面進行編織,修改目標類字節碼以應用於任何類型的方法調用。AspectJ 編織需要在類路徑中使用spring-aspects.jar 並啟用加載時編織(或編譯時編織)。(有關如何設置加載時編織的詳細信息,請參見Spring配置。) |
proxy-target-class |
proxyTargetClass |
false |
僅適用於代理模式。控制為使用@Transactional 註解註釋的類創建哪種類型的事務代理。如果proxy-target-class 屬性設置為true ,則將創建基於類的代理。如果proxy-target-class 為false 或省略了屬性,則將創建基於標準JDK接口的代理。(有關不同代理類型的詳細檢查,請參見代理機制。) |
order |
order |
Ordered.LOWEST_PRECEDENCE |
定義應用於帶@Transactional 註解的bean的事務通知的順序。(有關AOP通知排序相關規則的更多信息,請參見通知順序。)沒有指定的順序意味著AOP子系統確定通知的順序。 |
處理
@Transactional
註解的默認通知模式是代理,它僅允許通過代理攔截調用。同一類內的本地調用無法以這種方式被攔截(自調用)。對於更高級的攔截模式,請考慮結合編譯時或加載時編織切換到Aspectj
模式。
proxy-target-class
屬性控制為使用@Transactional
註解註釋的類創建哪種類型的事務代理。如果proxy-target-class
設置為true
,則將創建基於類的代理。如果proxy-target-class
為false
或省略了屬性,則將創建基於標準JDK接口的代理。(有關不同代理類型的討論,請參見core.html。)
@EnableTransactionManagement
和<tx:annotation-driven/>
僅在定義它們的相同應用程序上下文中的bean上查找@Transactional
。這意味著,如果將註解驅動的配置放在DispatcherServlet
的WebApplicationContext
中,它將僅在控制器而不是服務中檢查@Transactional
bean。有關更多信息,請參見MVC。
在評估方法的事務設置時,最派生的位置優先(譯者:範圍最小的優先級越高,例如:類和方法配置時方法優先級更高)。在下面的示例中,DefaultFooService
類在類級別使用只讀事務的設置進行註解,但是同一類中updateFoo(Foo)
方法上的@Transactional
註解優先於定義的事務設置在類級別上。
@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// ...
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// ...
}
}
@Transactional
設置
@Transactional
註解是元數據,它指定接口、類或方法必須具有事務語義(例如,在調用此方法時啟動一個全新的只讀事務、暫停任何現有事務
)。默認的@Transactional
設置如下:
- 事物傳播設置為
PROPAGATION_REQUIRED
。 - 事物隔離級別為
ISOLATION_DEFAULT
。 - 事務是讀寫的。
- 事務超時默認為基礎事務系統的默認超時,如果不支持超時,則默認為無。
- 任何
RuntimeException
都會觸發回滾,而任何檢測的Exception
都不會觸發。
你可以更改這些默認設置。下表總結了@Transactional
註解的各種屬性:
屬性 | 類型 | 描述 |
---|---|---|
value | String |
可選的限定符,指定要使用的事務管理器。 |
propagation |
enum : Propagation
|
可選的傳播設置。 |
isolation |
enum : Isolation
|
可選的隔離級別。僅適用於REQUIRED 或REQUIRES_NEW 的傳播值。 |
timeout |
int (以秒為單位) |
可選的事務超時。僅適用於REQUIRED 或REQUIRES_NEW 的傳播值。 |
readOnly |
boolean |
讀寫與只讀事務。僅適用於REQUIRED 或REQUIRES_NEW 的值。 |
rollbackFor |
Class對象數組,必須從Throwable 派生。 |
必須引起回滾的異常類的可選數組。 |
rollbackForClassName |
類名數組。這些類必須從Throwable 派生。 |
必須引起回滾的異常類名稱的可選數組。 |
noRollbackFor |
Class對象數組,必須從Throwable 派生。 |
不能導致回滾的異常類的可選數組。 |
noRollbackForClassName |
字符串類名稱的數組,必須從Throwable 派生。 |
不能引起回滾的異常類名稱的可選數組。 |
當前,你無法對事務名稱進行顯式控制,其中“名稱”是指顯示在事務監視器(如果適用)(例如,WebLogic
的事務監視器)和日誌輸出中的事務名稱。對於聲明式事務,事務名稱始終是全限定類名稱
+'.' +通知類的方法名稱
。例如,如果BusinessService
類的handlePayment(..)
方法啟動了事務,則事務的名稱將為:com.example.BusinessService.handlePayment
。
具有@Transactional的多個事務管理器
大多數Spring應用程序僅需要一個事務管理器,但是在某些情況下,你可能需要在一個應用程序中使用多個獨立的事務管理器。你可以使用@Transactional
註解的value
或transactionManager
屬性來選擇指定要使用的TransactionManager
。這可以是事務管理器bean的bean名稱或限定符值。例如,使用限定符表示法,可以在應用程序上下文中將以下Java代碼與以下事務管理器bean聲明進行組合:
public class TransactionalService {
@Transactional("order")
public void setSomething(String name) { ... }
@Transactional("account")
public void doSomething() { ... }
@Transactional("reactive-account")
public Mono<Void> doSomethingReactive() { ... }
}
以下清單顯示了bean聲明:
<tx:annotation-driven/>
<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>
<bean id="transactionManager3" class="org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager">
...
<qualifier value="reactive-account"/>
</bean>
</tx:annotation-driven>
在這種情況下,TransactionalService
上的各個方法在單獨的事務管理器下運行,並根據order
、account
和reactive-account
限定符進行區分。如果未找到特別限定的TransactionManager
bean,則仍使用默認的<tx:annotation-driven>
目標bean名稱transactionManager
。
參考代碼:
org.liyong.dataaccess.starter.QualifierAnnotationTransactionManagerIocContainer
自定義組合的註解
如果你發現在許多不同的方法上將@Transactional
重複使用相同的屬性,則Spring的元註解支持可讓你為特定用例定義自定義的註解。例如,考慮以下註解定義:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("order")
public @interface OrderTx {
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("account")
public @interface AccountTx {
}
前面的註解使我們可以按照上一節的內容編寫示例,如下所示:
public class TransactionalService {
@OrderTx
public void setSomething(String name) {
// ...
}
@AccountTx
public void doSomething() {
// ...
}
}
在前面的示例中,我們使用了語法來定義事務管理器限定符,但是我們還可以包括傳播行為,回滾規則、超時和其他功能。
參考代碼:
org.liyong.dataaccess.starter.CustomAnnotationTransactionManagerIocContainer
作者
個人從事金融行業,就職過易極付、思建科技、某網約車平臺等重慶一流技術團隊,目前就職於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分佈式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公眾號和博客站點對知識體系進行分享。關注公眾號:青年IT男 獲取最新技術文章推送!
博客地址: http://youngitman.tech
CSDN: https://blog.csdn.net/liyong1028826685
微信公眾號:
技術交流群: