spring-tx
目錄
Spring事務管理優勢
事務模型
全局事務
本地事務
Spring事務
事務抽象
通過事務實現資源同步
高級別的同步方法
低級別的同步方法TransactionAwareDataSourceProxy
聲明式事務管理
聲明式事務管理
聲明式事務管理實現
聲明式事務回滾
不同bean配置不同事務語義
設置
@Transactional
事務傳播
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_NESTED
編程式事務管理
TransactionTemplate
PlatformTransactionManager
事務綁定事件
Spring事務管理優勢
Spring框架支持全面的事務管理。Spring框架為事務管理提供了一致的抽象,具有以下優勢。
- ①跨越不同事務API的一致編程模型,如Java事務API ( JTA ) 、JDBC 、Hibernate 和Java 持久性API ( JPA ) 。
- ②支持聲明式事務管理。
- ③用于編程式事務管理的簡單API比復雜事務API(如JTA )要簡單。
- ④與Sp1ing的數據訪問抽象有極佳整合能力。
事務模型
全局事務
- 多個事務源
- JTA管理全局事務,API繁瑣,
本地事務
- 特定資源,無法跨多個事務源
- 侵入式編程
Spring事務
- 一致性編程,一次開發,多環境使用
- 編程式事務管理和聲明式事務管理。
事務抽象
Spring事務抽象的核心概念是事務策略。事務策略由org.springframework.transaction.PlatformTransactionManager 接口定義
public interface PlatformTransactionManager {
??? TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
??? void commit(TransactionStatus status) throws TransactionException;
??? void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction(..)方法根據TransactionDefinition 參數返回一個TransactionStatus 對象。返回的TransactionStatus 對象可能代表一個新的事務,或者是一個已經存在的事務(如果當前調用棧中存在匹配的事務) 。后一種情況的含義是,與JavaEE事務上下文一樣, TransactionStatus 與一個執行線程相關聯。
TransactionDefinition接口指定了如下定義。
- ①隔離( Isolation ) :代表了事務與其他事務的分離程度。例如,這個事務可以看到來自其他事務的未提交的寫入等。
- ②傳播(Propagation):通常,在事務范圍內執行的所有代碼都將在該事務中運行。但是,如果在事務上下文已經存在的情況下執行事務方法則可以選擇指定行為。例如,代碼可以在現有的事務中繼續運行(常見的情況),或者現有事務可以被暫停并創建新的事務。Spring提供了EJB? CMT 所熟悉的所有事務傳播選項。
- ③超時( Timeout ):
- ④只讀狀態( Read-only status ) : 當代碼讀取但不修改數據時,可以使用只讀事務。
TransactionStatus 接口為事務代碼提供了一種簡單的方法來控制事務執行和查詢事務狀態
public interface TransactionStatus extends SavepointManager {
??? boolean isNewTransaction();
??? boolean hasSavepoint();
??? void setRollbackOnly();
??? boolean isRollbackOnly();
??? void flush();
??? boolean isCompleted();
}
PlatformTransactionManager 實現通常需要知道它們的工作環境,如JDBC 、JTA 、Hibernate 等
JDBC:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
??? <property name="driverClassName" value="${jdbc.driverClassName}" />
??? <property name="url" value="${jdbc.url}" />
??? <property name="username" value="${jdbc.username}" />
??? <property name="password" value="${jdbc.password}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
??? <property name="dataSource" ref="dataSource"/>
</bean>
Hibernate:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
??? <property name="dataSource" ref="dataSource"/>
??? ... ...
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
??? <property name="sessionFactory" ref="sessionFactory"/>
</bean>
通過事務實現資源同步
高級別的同步方法
高級別的同步方法是首選的方法,通常是使用Spring 基于模板的持久性集成API ,或者是原生的ORM API 來管理本地的資源工廠。這些事務感知型解決方案在內部處理資驚創建和重用、清理、映射等,用戶無須關注這些細節。這樣,用戶可以純粹專注于非模板化的持久性邏輯。通常,可以使用原生的ORM API 或使用JdbcTemp late 采取模板方法進行JDBC 訪問。
低級別的同步方法
TransactionAwareDataSourceProxy
TransactionAwareDataSourceProxy 類是最低級別的。一般情況幾乎不需要使用這個類, 而是使用上面提到的更高級別的抽象來編寫新的代碼。這是目標DataSource 的代理,它封裝了目標DataSource 以增加對Spring管理的事務的感知。
聲明式事務管理
Spring 框架的聲明式事務管理是通過SpringAOP實現的,可以將事務行為指定到單個方法級別。如果需要,可以在事務上下文調用setRollbackOnly()方法。
聲明式事務管理
關于Spring框架的聲明式事務支持最重要的概念是通過AOP代理來啟用此支持,并且事務性的Advice由元數據(當前基于XML或基于注解的)驅動。AOP與事務性元數據的結合產生了AOP 代理,該代理使用TransactionInterceptor和適當的PlatformTransactionManager 實現來驅動方法調用周圍的事務。
調用事務代理的流程如下所示
聲明式事務管理實現
package x.y.service;
public interface FooService {
??? Foo getFoo(String fooName);
??? Foo getFoo(String fooName, String barName);
??? void insertFoo(Foo foo);
??? void updateFoo(Foo foo);
}
?
package x.y.service;
public class DefaultFooService implements FooService {
??? public Foo getFoo(String fooName) {
??????? throw new UnsupportedOperationException();
??? }
??? public Foo getFoo(String fooName, String barName) {
??????? throw new UnsupportedOperationException();
??? }
??? public void insertFoo(Foo foo) {
??????? throw new UnsupportedOperationException();
??? }
??? public void updateFoo(Foo foo) {
??????? throw new UnsupportedOperationException();
??? }
}
getFoo(String) and getFoo(String, String),運行在只讀語義,insertFoo(Foo) and updateFoo(Foo)運行在讀寫語義。
配置信息:
<?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">
??? <!--應用事務的對象-->
??? <bean id="fooService" class="x.y.service.DefaultFooService"/>
??? <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
??? <tx:advice id="txAdvice" transaction-manager="txManager">
??????? <!-- the transactional semantics... -->
??????? <tx:attributes>
??????????? <!-- 所有get*方法只讀 -->
??????????? <tx:method name="get*" read-only="true"/>
??????????? <!-- 其他方法-->
??????????? <tx:method name="*"/>
??????? </tx:attributes>
??? </tx:advice>
??? <!-- 配置 FooService 接口的所有方法都應用AOP-->
??? <aop:config>
??????? <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
??????? <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
??? </aop:config>
??? <!-- DataSource -->
??? <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
??????? <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
??????? <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
??????? <property name="username" value="scott"/>
??????? <property name="password" value="tiger"/>
??? </bean>
??? <!-- PlatformTransactionManager -->
??? <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
??????? <property name="dataSource" ref="dataSource"/>
??? </bean>
</beans>
使用對象:
public final class Boot {
??? public static void main(final String[] args) throws Exception {
??????? ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
??????? FooService fooService = (FooService) ctx.getBean("fooService");
??????? fooService.insertFoo (new Foo());
??? }
}
聲明式事務回滾
Spring事務回滾的推薦方式是拋出異常。在事務上下文中拋出異常,Spring會捕獲異常,并把事務標記為回滾。Spring默認僅在拋出RuntimeException,未受檢異常時,才會回滾事務。受檢的異常不會回滾事務。也可以精確地配置引起回滾的異常類型,包括受檢異常。
<tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/><tx:method name="*"/></tx:attributes> </tx:advice>也可指定不回滾事務的異常。
<tx:advice id="txAdvice"><tx:attributes><tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/><tx:method name="*"/></tx:attributes> </tx:advice>匹配回滾規則時,最強的規則勝出(匹配度最高)。
<!-- 除InstrumentNotFoundException之外的任何異常都會導致后續事務的回滾 --> <tx:advice id="txAdvice"><tx:attributes><tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/></tx:attributes> </tx:advice>也可以編碼回滾事務
public void resolvePosition() {
??? try {
??????? // some business logic...
??? } catch (NoProductInStockException ex) {
??????? // trigger rollback programmatically
??????? TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
??? }
}
不同bean配置不同事務語義
如果對很多個服務層對象應用完全不同的事務配置,可以通過配置不同的pointcut,advice-ref定義不同的<aop:advisor/>。
假定所有服務層對象都定義在x.y.service包,所有類都以service結尾,具有默認的事務配置,可以:
??? <aop:config>
?????? <!-- 切點:x.y.service包下所有*service類 -->
??????? <aop:pointcut id="serviceOperation"???????????????? expression="execution(* x.y.service..*Service.*(..))"/>
????? <!--? 上述切點應用? txAdvice-->
??????? <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
??? </aop:config>
??? <!-- these two beans will be transactional... -->
??? <bean id="fooService" class="x.y.service.DefaultFooService"/>
??? <bean id="barService" class="x.y.service.extras.SimpleBarService"/>
??? <!-- 沒有應用txAdvice -->
??? <bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->
??? <bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->
??? <tx:advice id="txAdvice">
??????? <tx:attributes>
??????????? <tx:method name="get*" read-only="true"/>
??????????? <tx:method name="*"/>
??????? </tx:attributes>
??? </tx:advice>
???
上述配置,主要是切點表達式的應用。切點與Advice的組合(Advisor)
<tx:advice/>設置
默認值:
- 傳播性:REQUIRED.
- 隔離級別: DEFAULT.
- 事務非只讀
- 超時默認
- 任何RuntimeException導致回滾, 受檢異常不回滾
| 屬性 | 必需 | 默認值 | 描述 |
| name | Yes | 應用事務的方法名稱,支持通配符(*),可以設置多個<tx:method>元素 | |
| propagation | No | REQUIRED | 事務傳播性 |
| isolation | No | DEFAULT | 隔離級別 |
| timeout | No | -1 | 事務超時(秒) |
| read-only | No | FALSE | 是否只讀 |
| rollback-for | No | 觸發回滾的異常列表,逗號分隔 | |
| no-rollback-for | No | 不觸發回滾的異常列表,逗號分隔 |
@Transactional
標準javax.transaction.Transactional可以作為Spring注解的一個替代。
@Transactional
public class DefaultFooService implements FooService {
??? Foo getFoo(String fooName);
??? Foo getFoo(String fooName, String barName);
??? void insertFoo(Foo foo);
??? void updateFoo(Foo foo);
}?? ?
等價:
??? <bean id="fooService" class="x.y.service.DefaultFooService"/>
??? <!-- 以下設置:啟用事務注解, transaction-manager指定事務管理器。latformTransactionManager類的實例的名稱為transactionManager,則不必設置transaction-manager屬性-->
??? <tx:annotation-driven transaction-manager="txManager"/>
??? <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
??????? <property name="dataSource" ref="dataSource"/>
??? </bean>
把@EnableTransactionManagement注解加在被@Configuration注解過的類上,也可以啟用事務管理。
應該將@Transactional加在public方法上,加在protected,private方法上,事務不會生效。
@Transactional可應用在接口,接口方法,類,類public方法上。但是僅有@Transactional不足以激活事務,它僅是定義了一些可以被事務感知型(@Transactional-aware)的基礎類使用的元數據,用以控制事務的行為。<tx:annotation-driven/>用以切換事務行為。
Spring建議僅用@Transactional注解具體類(或類的方法),也可以注解到接口或接口方法,但是僅在基于接口的代理類上才生效。基于類代理(proxy-target-class="true")或基于織入( mode="aspectj")的代理,不能識別事務,對象不會被事務Wrap。
在代理模式,僅通過代理的擴展方法能夠被攔截,意味著自調用(一個target方法調用此target的另一個方法),運行時會導致不正確的事務行為。
<tx:annotation-driven/>屬性
| XML屬性 | 注解屬性 | 默認值 | 描述 |
| transaction-manager | N/A (See TransactionManagementConfigurer javadocs) | transactionManager | 事務管理器名稱 |
| mode | mode | proxy | proxy:Spring AOP aspectj:AspectJ? |
| proxy-target-class | proxyTargetClass | FALSE | 僅mode為proxy有效。 True:class-based代理被創建。False:JDK interface-based代理被創建。 |
| order | order | Ordered.LOWEST_PRECEDENCE | AOP被應用的順序。 |
@EnableTransactionManagement 和 <tx:annotation-driven/>僅會查找定義在同一個application context,例如WebApplicationContext只會找定義在Controller上的@Transactional
方法注解優先于類注解。
@Transactional 設置
| Property | Type | Description |
| value | String | transactionManager |
| propagation | enum: Propagation | 事務傳播方式 |
| isolation | enum: Isolation | 事務隔離級別,只適用于 REQUIRED or EQUIRES_NEW. |
| timeout | int (in seconds of granularity) | 事務超時(秒),只適用于 REQUIRED or EQUIRES_NEW. |
| readOnly | boolean | 事務是否只讀,只適用于 REQUIRED or REQUIRES_NEW. |
| rollbackFor | Throwable子類列表 | 引起事務回滾的異常類列表 |
| rollbackForClassName | Throwable子類名稱列表 | 引起事務回滾的異常類名稱列表 |
| noRollbackFor | Throwable子類列表 | 不引起事務回滾的異常類列表 |
| noRollbackForClassName | Throwable子類名稱列表 | 不引起事務回滾的異常類名稱列表 |
目前,不能顯示定義事務的名稱,name屬性用于定義事務在事務監視器中的顯示名稱。聲明式事務的事務名稱是被增強類的全限定類名+'.'+方法名。例如BusinessService.handlePayment()應用一個事務,則事務名稱為*.BusinessService.handlePayment? 。
指定多個事務管理器
一個應用依賴都個事務管理器時,可以使用@Transactional的value屬性指定PlatformTransactionManager的實例。
public class TransactionalService {
??? @Transactional("order")
??? public void setSomething(String name) { ... }
??? @Transactional("account")
??? public void doSomething() { ... }
}
<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>
還可以使用元注解
@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() { ... }
}
?
事務傳播
PROPAGATION_REQUIRED
表示加入當前正要執行的事務不在另外一個事務中,那么就開啟一個新的事務。表示必須處于事務中。默認情況下,在加入外部事務時,會忽略隔離級別,超時,只讀標志。如果設置Transaction Manager的validateExistingTransactions為True,則在加入了一個只讀標志或隔離級別不同的事務,則會rejected。
PROPAGATION_REQUIRED應用于method2上。
PROPAGATION_REQUIRES_NEW
開啟一個新的事務,外部事務會被掛起。如果內部事務拋出的異常被外部事務截獲,則不會影響外部事務的提交。
?
PROPAGATION_NESTED
使用具有多個保存點的單個事務。子事務的開啟是通過保存點實現的,內部事務與外部事務是依賴的,內部事務回滾和提交不影響外部事務,但是外部事務的回滾引起內部事務回滾。
事務回滾
@Transcation 默認只回滾?拋出RuntimeException 及Error異常的事務,因此默認情況下如果拋出SQLException、IOException不進行處理的話是無法回滾事務的。
可以通過設置rollbackFor的方式指定哪些異常回滾
Error是一定會回滾的
三點結論:
?嵌套事務的回滾策略
事務嵌套回滾策略由事務的傳播行為(7種)決定,可以通過如下方式指定:
@Transactional(propagation = Propagation.REQUIRED)| PROPAGATION_REQUIRED | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是最常見的選擇。 | 外圍方法未開啟事務的情況下Propagation.REQUIRED修飾的內部方法會新開啟自己的事務,且開啟的事務相互獨立,互不干擾。外圍方法不會加入到任一事務 | 外圍方法開啟事務的情況下Propagation.REQUIRED修飾的內部方法會加入到外圍方法的事務中,所有Propagation.REQUIRED修飾的內部方法和外圍方法均屬于同一事務,只要一個方法回滾,整個事務均回滾。 |
| PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 | - | - |
| PROPAGATION_MANDATORY | 使用當前的事務,如果當前沒有事務,就拋出異常。強制需要事務 | - | - |
| PROPAGATION_REQUIRES_NEW | 一直新建事務,如果當前存在事務,把當前事務掛起。 | 同第一排PROPAGATION_REQUIRED | 開啟事務的情況下Propagation.REQUIRES_NEW修飾的內部方法依然會單獨開啟獨立事務,且與外部方法事務也獨立,內部方法之間、內部方法和外部方法事務均相互獨立,互不干擾。 |
| PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 | - | - |
| PROPAGATION_NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常。 | - | - |
| PROPAGATION_NESTED | 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 | 同第一排PROPAGATION_REQUIRED | 外圍方法開啟事務的情況下Propagation.NESTED修飾的內部方法屬于外部事務的子事務,外圍主事務回滾,子事務一定回滾,而內部子事務可以單獨回滾而不影響外圍主事務和其他子事務 |
事務方法調用自己類下面的其它方法
?
@Override@Transactional(propagation = Propagation.REQUIRED)public int insert(User user) {try {int insert = userMapper.insert(user);this.update();//調用本類中其它添加了事務注解的方法,導致update事務不生效return insert;} catch (Exception e){throw new RuntimeException();}}@Override@Transactional(propagation = Propagation.REQUIRED)public int update() {try {return userMapper.update();} catch (Exception e){throw new RuntimeException();}}update事務失效是因為調用的動態代理類的增強方法,該方法內調用實際被增強類的方法,方法內this.xxx();,并不是使用的代理類。
?
解決方法:
使用增強后的代理類調用該方法,使用@Autowired或從spring容器獲取bean,如果該Service加了事務注解,拿到的bean類型其實就是$ProxyXX等代理類并不是我們自己寫的Service
如果使用的是springBoot,在啟動類添加:@EnableAspectJAutoProxy(ExposeProxy=true) 在通過
AopContext.currentProxy()可以拿到當前類的代理類;?
編程式事務管理
Spring提供2種編程式事務管理方式:
- TransactionTemplate
- 直接實現PlatformTransactionManager
TransactionTemplate
TransactionTemplate采用與其他Spring模板(如JdbcTemplate)相同的方法。它使用一種回調方法,使應用程序代碼可以處理獲取和釋放事務資源,這樣可以讓開發人員更加專注于自己的業務邏輯的編寫。
應用代碼必須在事務上下文中執行,并且顯示使用TransactionTemplate,execute()方法的參數為TransactionCallback的實現。
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 executes in a transactional context
??????????? public Object doInTransaction(TransactionStatus status) {
??????????????? updateOperation1();
??????????????? return resultOfUpdateOperation2();
??????????? }
??????? });
??? }
}
//如果沒有返回值,則使用TransactionCallbackWithoutResult
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
??? protected void doInTransactionWithoutResult(TransactionStatus status) {
??????? updateOperation1();
??????? updateOperation2();
??? }
});
//如果回滾事務,則設置setRollbackOnly
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
??? protected void doInTransactionWithoutResult(TransactionStatus status) {
??????? try {
??????????? updateOperation1();
??????????? updateOperation2();
??????? } catch (SomeBusinessException ex) {
??????????? status.setRollbackOnly();
??????? }
??? }
});
指定事務設置
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...
??? }
}
//
//XML設置方式
<bean id="sharedTransactionTemplate"
??????? class="org.springframework.transaction.support.TransactionTemplate">
??? <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
??? <property name="timeout" value="30"/>
</bean>"
PlatformTransactionManager
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 {
??? // execute your business logic here
}
catch (MyException ex) {
??? txManager.rollback(status);
??? throw ex;
}
txManager.commit(status);
事務綁定事件
從Spring 4.2 開始,事件的監昕器可以被綁定到事務的某個階段。一個典型的應用場景是在事務成功完成時處理事件。注冊常規的事件監聽器是通過@EventListener 注解完成的。如果要將其綁定到特定的事務中,則使用@TransactionalEventListener 。默認情況下,監聽器將被綁定到事務的提交階段。
@Component
public class MyComponent {
??? //在事務提交時,執行此方法
??? @TransactionalEventListener
??? public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
??????? ...
??? }
}
設置phase屬性,值為:
- BEFORE_COMMIT
- AFTER_COMMIT (default)
- AFTER_ROLLBACK
- AFTER_COMPLETION(無論提交還是回滾)
?
?
?
?
?
?
總結
- 上一篇: spring-JDBC
- 下一篇: Spring--IoC(1)