日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring-tx

發(fā)布時間:2024/4/13 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring-tx 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

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)值描述
nameYes 應(yīng)用事務(wù)的方法名稱,支持通配符(*),可以設(shè)置多個<tx:method>元素
propagationNoREQUIRED事務(wù)傳播性
isolationNoDEFAULT隔離級別
timeoutNo-1事務(wù)超時(秒)
read-onlyNoFALSE是否只讀
rollback-forNo 觸發(fā)回滾的異常列表,逗號分隔
no-rollback-forNo 不觸發(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-managerN/A (See TransactionManagementConfigurer javadocs)transactionManager事務(wù)管理器名稱
modemodeproxyproxy:Spring AOP
aspectj:AspectJ?
proxy-target-classproxyTargetClassFALSE僅mode為proxy有效。
True:class-based代理被創(chuàng)建。False:JDK interface-based代理被創(chuàng)建。
orderorderOrdered.LOWEST_PRECEDENCEAOP被應(yīng)用的順序。

@EnableTransactionManagement 和 <tx:annotation-driven/>僅會查找定義在同一個application context,例如WebApplicationContext只會找定義在Controller上的@Transactional

方法注解優(yōu)先于類注解。

@Transactional 設(shè)置

PropertyTypeDescription
valueStringtransactionManager
propagationenum: Propagation事務(wù)傳播方式
isolationenum: Isolation事務(wù)隔離級別,只適用于 REQUIRED or EQUIRES_NEW.
timeoutint (in seconds of granularity)事務(wù)超時(秒),只適用于 REQUIRED or EQUIRES_NEW.
readOnlyboolean事務(wù)是否只讀,只適用于 REQUIRED or REQUIRES_NEW.
rollbackForThrowable子類列表引起事務(wù)回滾的異常類列表
rollbackForClassNameThrowable子類名稱列表引起事務(wù)回滾的異常類名稱列表
noRollbackForThrowable子類列表不引起事務(wù)回滾的異常類列表
noRollbackForClassNameThrowable子類名稱列表不引起事務(wù)回滾的異常類名稱列表

目前,不能顯示定義事務(wù)的名稱,name屬性用于定義事務(wù)在事務(wù)監(jiān)視器中的顯示名稱。聲明式事務(wù)的事務(wù)名稱是被增強類的全限定類名+'.'+方法名。例如BusinessService.handlePayment()應(yīng)用一個事務(wù),則事務(wù)名稱為*.BusinessService.handlePayment? 。

指定多個事務(wù)管理器

一個應(yīng)用依賴都個事務(wù)管理器時,可以使用@Transactionalvalue屬性指定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也一樣會回滾 @Transactional(rollbackFor = Exception.class)

Error是一定會回滾的
三點結(jié)論:

  • 當(dāng)我們拋出的異常為RunTime及其子類或者Error和其子類的時候。不論rollbackFor的異常是啥,都會進(jìn)行事務(wù)的回滾。
  • 當(dāng)我們拋出的異常不是RunTime及其子類或者Error和其子類的時候,必須根據(jù)rollbackfor進(jìn)行回滾。比如rollbackfor=RuntimeException,而拋出IOException時候,事務(wù)是不進(jìn)行回滾的。
  • 當(dāng)我們拋出的異常不是RunTime及其子類或者Error和其子類的時候,如果嵌套事務(wù)中,只要有一個rollbackfor允許回滾,則整個事務(wù)回滾。
  • ?嵌套事務(wù)的回滾策略

    事務(wù)嵌套回滾策略由事務(wù)的傳播行為(7種)決定,可以通過如下方式指定:

    @Transactional(propagation = Propagation.REQUIRED) 事務(wù)傳播行為類型說明外圍方法不開啟事務(wù)外圍方法開啟事務(wù)
    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)前類的代理類;?

    @Autowiredprivate UserService userService;@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ù)不生效userService.update();//替換為調(diào)用增強類的方法return insert;} catch (Exception e){throw new RuntimeException();}}

    編程式事務(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-tx的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。