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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 事务原理和使用

發(fā)布時間:2023/12/3 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 事务原理和使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載自??Spring 事務原理和使用

1.Spring@Transactional的配置

步驟一、在Spring配置文件中引入命名空間

<beans?xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

步驟二、xml配置文件中,添加事務管理器bean配置

<!--?事務管理器配置,單數(shù)據(jù)源事務?--><bean?id="pkgouTransactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property?name="dataSource"?ref="pkGouDataSource"?/></bean> <!--?使用annotation定義事務?--><tx:annotation-driven?transaction-manager="pkgouTransactionManager"?/>

步驟三、在使用事務的方法或者類上添加下面的注解

@Transactional(“pkgouTransactionManager”)

?

2.傳播行為和隔離級別

1> 事務注解方式: @Transactional

  • 標注在類前:標示類中所有方法都進行事務處理

  • 標注在接口、實現(xiàn)類的方法前:標示方法進行事務處理

2> 事務傳播行為介紹:

?

3> 事務超時設置:

@Transactional(timeout=30)?//默認是30秒

4> 事務隔離級別:

?

  • 臟讀 : 一個事務讀取到另一事務未提交的更新數(shù)據(jù)

  • 不可重復讀 : 在同一事務中, 多次讀取同一數(shù)據(jù)返回的結果有所不同, 換句話說, 后續(xù)讀取可以讀到另一事務已提交的更新數(shù)據(jù)。相反,”可重復讀”在同一事務中多次讀取數(shù)據(jù)時,能夠保證所讀數(shù)據(jù)一樣,也就是后續(xù)讀取不能讀到另一事務已提交的更新數(shù)據(jù)

  • 幻讀 : 一個事務讀到另一個事務已提交的insert數(shù)據(jù)

@Transactional的屬性:

?

3.工作原理

自動提交

默認情況下,數(shù)據(jù)庫處于自動提交模式。每一條語句處于一個單獨的事務中,在這條語句執(zhí)行完畢時,如果執(zhí)行成功則隱式的提交事務,如果執(zhí)行失敗則隱式的回滾事務。 事務管理,是一組相關的操作處于一個事務之中,因此必須關閉數(shù)據(jù)庫的自動提交模式。這點,Spring會在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中將底層連接的自動提交特性設置為false。

//?switch?to?manual?commit?if?necessary。?this?is?very?expensive?in?some?jdbc?drivers, //?so?we?don't?want?to?do?it?unnecessarily?(for?example?if?we've?explicitly //?configured?the?connection?pool?to?set?it?already)。if?(con。getautocommit())? {txobject.setmustrestoreautocommit(true);if?(logger.isdebugenabled())?{logger.debug("switching?jdbc?connection?["?+?con?+?"]?to?manual?commit");}//首先將自動提交屬性改為falsecon.setautocommit(false); }

spring事務回滾規(guī)則

Spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內(nèi)拋出異常。Spring事務管理器會捕捉任何未處理的異常,然后依據(jù)規(guī)則決定是否回滾拋出異常的事務。 默認配置下,Spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾)。而拋出checked異常則不會導致事務回滾。 Spring也支持明確的配置在拋出哪些異常時回滾事務,包括checked異常。也可以明確定義哪些異常拋出時不回滾事務。 還可以編程性的通過setRollbackOnly()方法來指示一個事務必須回滾,在調(diào)用完setRollbackOnly()后你所能執(zhí)行的唯一操作就是回滾。

4.注意事項

由于Spring事務管理是基于接口代理或動態(tài)字節(jié)碼技術,通過AOP實施事務增強的。

(1)對于基于接口動態(tài)代理的AOP事務增強來說,由于接口的方法是public的,這就要求實現(xiàn)類的實現(xiàn)方法必須是public的(不能是protected,private等),同時不能使用static的修飾符。所以,可以實施接口動態(tài)代理的方法只能是使用“public” 或 “public final”修飾符的方法,其它方法不可能被動態(tài)代理,相應的也就不能實施AOP增強,也即不能進行Spring事務增強。

(2)基于CGLib字節(jié)碼動態(tài)代理的方案是通過擴展被增強類,動態(tài)創(chuàng)建子類的方式進行AOP增強植入的。由于使用final,static,private修飾符的方法都不能被子類覆蓋,相應的,這些方法將不能被實施的AOP增強。

所以,必須特別注意這些修飾符的使用,@Transactional 注解只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯,但是這個被注解的方法將不會展示已配置的事務設置。

用 spring 事務管理器,由spring來負責數(shù)據(jù)庫的打開,提交,回滾。默認遇到運行期異常(throw new RuntimeException(“注釋”);)會回滾,即遇到不受檢查(unchecked)的異常時回滾;

@Transactional(rollbackFor=Exception.class)?//指定回滾,遇到異常Exception時回滾 public?void?methodName()? { throw?new?Exception("注釋"); }

而遇到需要捕獲的異常(throw new Exception(“注釋”);)不會回滾,即遇到受檢查的異常(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查異常或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional(rollbackFor={Exception。class,其它異常}) 。如果讓unchecked異常不回滾:

@Transactional(notRollbackFor=RunTimeException.class)如下:@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期異常(throw?new?RuntimeException("注釋");)會回滾 public?ItimDaoImpl?getItemDaoImpl()? { throw?new?RuntimeException("注釋"); }

僅僅 @Transactional注解的出現(xiàn)不足于開啟事務行為,它僅僅是一種元數(shù)據(jù),能夠被可以識別 @Transactional注解和上述的配置適當?shù)木哂惺聞招袨榈腷eans所使用。其實,根本上是 元素的出現(xiàn) 開啟了事務行為。

Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現(xiàn)的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基于接口的代理時它才生效。因為注解是不能繼承的,這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,請接受Spring團隊的建議并且在具體的類火方法上使用 @Transactional 注解。

@Transactional 注解標識的方法,處理過程盡量的簡單。尤其是帶鎖的事務方法,能不放在事務里面的最好不要放在事務里面。可以將常規(guī)的數(shù)據(jù)庫查詢操作放在事務前面進行,而事務內(nèi)進行增、刪、改、加鎖查詢等操作。

@Transactional 注解的默認事務管理器bean是“transactionManager”,如果聲明為其他名稱的事務管理器,需要在方法上添加@Transational(“managerName”)。

@Transactional 注解標注的方法中不要出現(xiàn)網(wǎng)絡調(diào)用、比較耗時的處理程序,因為,事務中數(shù)據(jù)庫連接是不會釋放的,如果每個事務的處理時間都非常長,那么寶貴的數(shù)據(jù)庫連接資源將很快被耗盡。

5.自我調(diào)用中的問題?

Spring事務使用AOP代理后的方法調(diào)用執(zhí)行流程,如圖所示:

?

從圖中可以看出,調(diào)用事務時首先調(diào)用的是AOP代理對象而不是目標對象,首先執(zhí)行事務切面,事務切面內(nèi)部通過TransactionInterceptor環(huán)繞增強進行事務的增強。即進入目標方法之前開啟事務,退出目標方法時提交/回滾事務。

這樣在自我調(diào)用時,則會出現(xiàn)無法開啟事務的問題,比如:

public?interface?TargetService? {??public?void?a();??public?void?b();?? }?? @Service? public?class?TargetServiceImpl?implements?TargetService {??public?void?a()?{??this.b();??}??@Transactional(propagation?=?Propagation.REQUIRES_NEW)??public?void?b()?{//執(zhí)行數(shù)據(jù)庫操作}?? }

此處的this指向目標對象,因此調(diào)用this.b()將不會執(zhí)行b事務切面,即不會執(zhí)行事務增強,因此b方法的事務定義“@Transactional(propagation = Propagation.REQUIRES_NEW)”將不會實施,即結果是b和a方法的事務是方法的事務定義是一樣的。

解決方法 通過BeanPostProcessor 在目標對象中注入代理對象:

一、定義BeanPostProcessor 需要使用的標識接口

public?interface?BeanSelfAware {public?abstract?void?setSelf(Object?obj); }

二、定義自己的BeanPostProcessor(InjectBeanSelfProcessor)

public?class?InjectBeanSelfProcessorimplements?BeanPostProcessor,?ApplicationContextAware {ApplicationContext?context;private?static?Log?log?=?LogFactory.getLog(com/netease/lottery/base/common/BeanSelf/InjectBeanSelfProcessor); public?InjectBeanSelfProcessor() { } public?void?setApplicationContext(ApplicationContext?context)throws?BeansException {this.context?=?context; } public?Object?postProcessAfterInitialization(Object?bean,?String?beanName)throws?BeansException {if(bean?instanceof?BeanSelfAware){//如果Bean實現(xiàn)了BeanSelfAware標識接口,就將代理對象注入BeanSelfAware?myBean?=?(BeanSelfAware)bean;Class?cls?=?bean.getClass();if(!AopUtils.isAopProxy(bean)){Class?c?=?bean.getClass();Service?serviceAnnotation?=?(Service)c.getAnnotation(org/springframework/stereotype/Service);if(serviceAnnotation?!=?null)try{bean?=?context.getBean(beanName);if(AopUtils.isAopProxy(bean));}catch(BeanCurrentlyInCreationException?beancurrentlyincreationexception)?{?}catch(Exception?ex){log.fatal((new?StringBuilder()).append("No?Proxy?Bean?for?service?").append(bean.getClass()).append("?").append(ex.getMessage()).toString(),?ex);}}myBean.setSelf(bean);return?myBean;}?else{return?bean;} } public?Object?postProcessBeforeInitialization(Object?bean,?String?beanName)throws?BeansException {return?bean; }

三、目標類實現(xiàn)

public?interface?TargetService? {?? public?void?a();?? public?void?b();?? }?? @Service? public?class?TargetServiceImpl?implements?TargetService,BeanSelfAware {?? private?TargetService?self;?? public?void?setSelf(Object?proxyBean)? {?//通過InjectBeanSelfProcessor注入自己(目標對象)的AOP代理對象??this.self?=?(TargetService)?proxyBean;?? }?? public?void?a()? {??self.b();?? }?? @Transactional(propagation?=?Propagation.REQUIRES_NEW)?? public?void?b()? { //執(zhí)行數(shù)據(jù)庫操作 }?? }

postProcessAfterInitialization根據(jù)目標對象是否實現(xiàn)BeanSelfAware標識接口,通過setSelf(bean)將代理對象(bean)注入到目標對象中,從而可以完成目標對象內(nèi)部的自我調(diào)用。

總結

以上是生活随笔為你收集整理的Spring 事务原理和使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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