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