成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深刻理解Spring聲明式事務(wù)

Cheng_Gang / 947人閱讀

摘要:支持聲明式事務(wù),通過注解控制方法是否支持事務(wù)。聲明式事務(wù),基于實現(xiàn),將具體業(yè)務(wù)和業(yè)務(wù)邏輯解耦。該級別下事務(wù)順序執(zhí)行,阻止上面的缺陷,開銷很大。

問題引入

  1. Spring中事務(wù)傳播有哪幾種,分別是怎樣的?
  2. 理解注解事務(wù)的自動配置?
  3. SpringBoot啟動類為什么不需要加@EnableTransactionManagement注解?
  4. 聲明式事務(wù)的實現(xiàn)原理?(待補充)

1 聲明式事務(wù)

系統(tǒng)開發(fā)中必然與數(shù)據(jù)打交道,事務(wù)管理必不可少。Spring支持聲明式事務(wù),通過@Transactional注解控制方法是否支持事務(wù)。聲明式事務(wù),基于AOP實現(xiàn),將具體業(yè)務(wù)和業(yè)務(wù)邏輯解耦。

Spring提供了@EnableTransactionManagement注解在配置類(啟動類)上啟用支持事務(wù),此時Spring會自動掃描具有@Transactional注解的類和方法。該注解相當于xml配置方式的 。通過設(shè)置mode屬性,決定使用spring代理,還是ASPECTJ擴展。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement {   boolean proxyTargetClass() default false;   AdviceMode mode() default AdviceMode.PROXY; // 代理模式   int order() default Ordered.LOWEST_PRECEDENCE; // LOWEST_PRECEDENCE最低優(yōu)先級,所以在執(zhí)行鏈的最外面,而自己實現(xiàn)的AOP攔截器優(yōu)先級都高于事務(wù),所以被嵌套在里面,越貼近業(yè)務(wù)代碼。}

2 @Transactional注解的使用

2.1 @Transactional注解屬性

@Transactional注解可以應(yīng)用于類和方法。聲明類時,該注解默認作用于類和子類的所有方法,應(yīng)用于public方法才有效;父類方法要加入同等級別的注解,需要多帶帶聲明。

@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Transactional {	@AliasFor("transactionManager")	String value() default "";        // 用來確定目標事務(wù)管理器	@AliasFor("value")	String transactionManager() default "";    // 事務(wù)的傳播,默認Propagation.REQUIRED	Propagation propagation() default Propagation.REQUIRED;    // 事務(wù)隔離級別,默認是Isolation.DEFAULT	Isolation isolation() default Isolation.DEFAULT;    // 事務(wù)超時時間,默認是-1	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;    // 指定事務(wù)是否為只讀事務(wù),默認為false,僅僅是個提示	boolean readOnly() default false;    // 標識能觸發(fā)事務(wù)回滾的異常類型,默認是RuntimeException和Error,不包含檢查異常。	Class[] rollbackFor() default {};	// 標識哪些異常不需要回滾事務(wù)	Class[] noRollbackFor() default {};	String[] noRollbackForClassName() default {};	String[] rollbackForClassName() default {};}

其中,isolation和timeout兩個屬性僅對新啟動的事務(wù)有效,專為Propagation.REQUIRED和Propagation.REQUIRES_NEW使用而設(shè)計。

2.2 事務(wù)的傳播行為-Propagation

Propagation定義了事務(wù)的傳播,一共有7種級別。

public enum Propagation {	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),	NEVER(TransactionDefinition.PROPAGATION_NEVER),	NESTED(TransactionDefinition.PROPAGATION_NESTED);	private final int value;	Propagation(int value) {		this.value = value;	}	public int value() {		return this.value;	}}
  • REQUIRED:使用當前的事務(wù),如果當前沒有事務(wù),則自己新建一個事務(wù),子方法是必須運行在一個事務(wù)中的;如果當前存在事務(wù),則加入這個事務(wù),成為一個整體。
    舉例:領(lǐng)導(dǎo)沒飯吃,我有錢,那么我會自己買了吃;領(lǐng)導(dǎo)有的吃,會分給你一起吃。
  • SUPPORTS:如果當前有事務(wù),則使用事務(wù);如果當前沒有事務(wù),則不使用事務(wù)。多用于查詢。
    舉例:領(lǐng)導(dǎo)沒飯吃,我也沒飯吃;領(lǐng)導(dǎo)有飯吃,我也有飯吃。
  • MANDATORY:傳播屬性強制必須存在一個事務(wù),如果不存在,則會拋出異常。
    舉例:領(lǐng)導(dǎo)必須管飯,不管飯就沒飯吃,我就不干了(就會拋出異常)。
  • REQUIRES_NEW:如果當前有事務(wù),則掛起該事務(wù),并且自己創(chuàng)建一個新的事務(wù)給自己使用;如果當前沒有事務(wù),則同 REQUIRED
    舉例:領(lǐng)導(dǎo)有飯吃,我偏不要,自己買東西自己吃
    • 1.標志REQUIRES_NEW會新開啟事務(wù),外層事務(wù)不會影響內(nèi)部事務(wù)的提交/回滾。內(nèi)部提交修改,會導(dǎo)致A的臟讀。
    • 2.標志REQUIRES_NEW的內(nèi)部事務(wù)異常,會影響外部事務(wù)的回滾
  • NOT_SUPPORTED:如果當前有事務(wù),則把事務(wù)掛起,自己不使用事務(wù)運行數(shù)據(jù)庫操作
    舉例:領(lǐng)導(dǎo)有飯吃,分一點給你,我太忙了,放一邊,我不吃
  • NEVER:如果當前有事務(wù)存在,則拋出異常
    舉例:領(lǐng)導(dǎo)有飯給你吃,我不想吃,果斷拋出異常
  • NESTED:如果當前存在事務(wù),則開啟子事務(wù)(嵌套事務(wù));如果當前沒有事務(wù),則同 REQUIRED。但是如果主事務(wù)提交,則會攜帶子事務(wù)一起提交。如果主事務(wù)回滾,則子事務(wù)會一起回滾。相反,子事務(wù)異常,則父事務(wù)可以回滾或不回滾(trycatch)。
    舉例:領(lǐng)導(dǎo)決策不對,老板怪罪,領(lǐng)導(dǎo)帶著小弟一同受罪;小弟出了差錯,領(lǐng)導(dǎo)可以推卸責任。

區(qū)分NESTED與REQUIRES_NEW

最根本的區(qū)別是NESTED還在一個事務(wù)中,但是與主事務(wù)一塊提交。

// TransactionalServiceImpl@Transactional(propagation = Propagation.REQUIRED)@Overridepublic void testPropagation() {    stuService.saveParent();    stuService.saveChildren();    int a = 1 / 0;}// StuServiceImpl/* 測試事務(wù)傳播 */@Transactional(propagation = Propagation.NESTED) // 切換NESTED/REQUIRES_NEW@Overridepublic void saveParent() {	Stu stu = new Stu();	stu.setName("parent");	stu.setScore(100);	stuMapper.insert(stu);}@Transactional(propagation = Propagation.NESTED)@Overridepublic void saveChildren() {	saveChild1();	int a = 1 / 0;	saveChild2();}

一個容易疏漏的點

在代理模式(默認)下,僅攔截通過代理傳入的外部方法調(diào)用。這意味著同一個目標對象內(nèi)部的方法調(diào)用,即使調(diào)用的方法標記有@Transactional,也不會在運行時導(dǎo)致事務(wù)攔截。

// 同一個類@Transactional(propagation = Propagation.REQUIRED)@Overridepublic void saveChildren() {    saveChild1();    int a = 1 / 0;    saveChild2();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void saveChild1() {    Stu stu = new Stu();    stu.setName("child-1");    stu.setScore(60);    stuMapper.insert(stu);}

參考官方文檔

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.在代理模式下(默認),只有通過代理進入的外部方法調(diào)用才會被攔截。 這意味著自調(diào)用實際上是目標對象中的一個方法調(diào)用目標對象的另一個方法,即使被調(diào)用的方法用@Transactional 標記,也不會在運行時導(dǎo)致實際事務(wù)。 此外,代理必須完全初始化以提供預(yù)期的行為,因此您不應(yīng)在初始化代碼中依賴此功能,即@PostConstruct。

2.3 事務(wù)的隔離級別-Isolation

public enum Isolation {	DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),	READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED), 	READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED), 	REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ), 	SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);	private final int value;	Isolation(int value) {		this.value = value;	}	public int value() {		return this.value;	}}

Spring事務(wù)隔離級別共有5種,隔離級別的設(shè)置依賴當前數(shù)據(jù)庫是否支持。

  • DEFAULT:使用當前數(shù)據(jù)庫的默認隔離級別。例如Oracle是READ_COMMITED,MySQL是READ_REPEATED。
  • READ_UNCOMMITED:可導(dǎo)致臟讀、不可重復(fù)讀、幻讀。
  • READ_COMMITTED:阻止臟讀,可導(dǎo)致不可重復(fù)讀、幻讀。
  • REPEATABLE_READ:阻止臟讀和不可重復(fù)讀,可導(dǎo)致幻讀。
  • SERIALIZABLE:該級別下事務(wù)順序執(zhí)行,阻止上面的缺陷,開銷很大。

3 SpringBoot啟動類為什么不需要加@EnableTransactionManagement注解

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

SpringBoot加載spring.factories時,會加載事務(wù)配置類TransactionAutoConfiguration,內(nèi)部有開啟事務(wù)管理的配置。

// ~TransactionAutoConfiguration中的內(nèi)部類@Configuration(proxyBeanMethods = false)@ConditionalOnBean(TransactionManager.class)@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)public static class EnableTransactionManagementConfiguration {	@Configuration(proxyBeanMethods = false)	@EnableTransactionManagement(proxyTargetClass = false)	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",			matchIfMissing = false)	public static class JdkDynamicAutoProxyConfiguration {	}	@Configuration(proxyBeanMethods = false)	@EnableTransactionManagement(proxyTargetClass = true)	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",			matchIfMissing = true)	public static class CglibAutoProxyConfiguration {	}}

4 Spring聲明式事務(wù)的內(nèi)部實現(xiàn)機制

在應(yīng)用系統(tǒng)調(diào)用聲明@Transactional 的目標方法時,Spring Framework 默認使用 AOP 代理,結(jié)合AOP和事務(wù)元數(shù)據(jù)(注解)在代碼運行時生成一個代理對象,根據(jù)@Transactional 的屬性配置信息,這個代理對象決定該聲明@Transactional 的目標方法是否由攔截器 TransactionInterceptor 來使用攔截,在 TransactionInterceptor 攔截時,會在目標方法開始執(zhí)行之前創(chuàng)建并加入事務(wù),并執(zhí)行目標方法的邏輯, 最后根據(jù)執(zhí)行情況是否出現(xiàn)異常,利用抽象事務(wù)管理器AbstractPlatformTransactionManager 操作數(shù)據(jù)源 DataSource 提交或回滾事務(wù)。

事務(wù)管理的框架是由抽象事務(wù)管理器 AbstractPlatformTransactionManager 來提供的,而具體的底層事務(wù)處理實現(xiàn)由 PlatformTransactionManager 的具體實現(xiàn)類來實現(xiàn),如事務(wù)管理器 DataSourceTransactionManager。不同的事務(wù)管理器管理不同的數(shù)據(jù)資源 DataSource,比如 DataSourceTransactionManager 管理 JDBC 的 Connection。

參考文檔

  1. https://www.cnblogs.com/xd502djj/p/10940627.html
  2. https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/124120.html

相關(guān)文章

  • Spring編程聲明事務(wù)實例講解

    摘要:基于和命名空間的聲明式事務(wù)管理目前推薦的方式,其最大特點是與結(jié)合緊密,可以充分利用切點表達式的強大支持,使得管理事務(wù)更加靈活?;诘娜⒔夥绞綄⒙暶魇绞聞?wù)管理簡化到了極致。 Java面試通關(guān)手冊(Java學(xué)習指南):https://github.com/Snailclimb/Java_Guide 歷史回顧:可能是最漂亮的Spring事務(wù)管理詳解 Spring事務(wù)管理 Spring支持兩...

    lushan 評論0 收藏0
  • Java項目經(jīng)驗——程序員成長的鑰匙

    摘要:當你真正到公司里面從事了幾年開發(fā)之后,你就會同意我的說法利用找工作,需要的就是項目經(jīng)驗,項目經(jīng)驗就是理解項目開發(fā)的基本過程,理解項目的分析方法,理解項目的設(shè)計思 Java就是用來做項目的!Java的主要應(yīng)用領(lǐng)域就是企業(yè)級的項目開發(fā)!要想從事企業(yè)級的項目開發(fā),你必須掌握如下要點: 1、掌握項目開發(fā)的基本步驟 2、具備極強的面向?qū)ο蟮姆治雠c設(shè)計技巧 3、掌握用例驅(qū)動、以架構(gòu)為核心的主流開發(fā)...

    zhangfaliang 評論0 收藏0
  • SpringBoot 實戰(zhàn) (十) | 聲明事務(wù)

    摘要:前言如題,今天介紹的聲明式事務(wù)。提供一個注解在配置類上來開啟聲明式事務(wù)的支持。而在配置里還開啟了對聲明式事務(wù)的支持,代碼如下所以在中,無須顯式開啟使用注解。源碼下載后語以上為聲明式事務(wù)的教程。 微信公眾號:一個優(yōu)秀的廢人如有問題或建議,請后臺留言,我會盡力解決你的問題。 前言 如題,今天介紹 SpringBoot 的 聲明式事務(wù)。 Spring 的事務(wù)機制 所有的數(shù)據(jù)訪問技術(shù)都有事務(wù)處...

    ygyooo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<