免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
事務(wù)的傳播行為&&嵌套事務(wù)的使用

一、前言:

事務(wù)的傳播行為(propagation)就是為了解決外層方法調(diào)用內(nèi)層事務(wù)方法的各個(gè)情況的。

接下來(lái)要說(shuō)的嵌套事務(wù)的使用是基于Spring聲明式事務(wù)管理中的注解@Transactional 方式的。

二、事務(wù)的傳播行為:

  1. @Transactional(propagation=Propagation.REQUIRED) :如果外層調(diào)用方法本身有事務(wù), 那么就加入到該事務(wù)中, 沒(méi)有的話新建一個(gè)(這是默認(rèn)的設(shè)置項(xiàng))
  2. @Transactional(propagation=Propagation.NOT_SUPPORTED) :以非事務(wù)方式運(yùn)行,如果外層調(diào)用方法存在事務(wù),則把當(dāng)這個(gè)事務(wù)掛起。
  3. @Transactional(propagation=Propagation.REQUIRES_NEW) :不管外層調(diào)用方法否存在事務(wù),都創(chuàng)建一個(gè)自己的事務(wù),外層調(diào)用方法的事務(wù)掛起,自己的執(zhí)行完畢,再執(zhí)行調(diào)用方事務(wù)
  4. @Transactional(propagation=Propagation.MANDATORY) :如果外層調(diào)用方法存在事務(wù),則加入該事務(wù);如果外層調(diào)用方法沒(méi)有事務(wù),則拋出異常
  5. @Transactional(propagation=Propagation.NEVER) :以非事務(wù)方式運(yùn)行,如果外層調(diào)用方法存在事務(wù),則拋出異常。
  6. @Transactional(propagation=Propagation.SUPPORTS) :如果外層調(diào)用方法存在事務(wù),則加入該事務(wù);如果外層調(diào)用方法沒(méi)有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
  7. @Transactional(propagation=Propagation.NESTED) :如果外層調(diào)用方法存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果外層調(diào)用方法沒(méi)有事務(wù),則該取值等價(jià)于TransactionDefinition.PROPAGATION_REQUIRED

 

三、關(guān)于事務(wù)傳播行為:

傳播行為就是一個(gè)約定:“別的方法調(diào)用自己的時(shí)候會(huì)以怎樣的方式開(kāi)啟事務(wù)”。

當(dāng)你給一個(gè)方法指定傳播行為的時(shí)候這時(shí)這個(gè)方法本身肯定是支持事務(wù)的方法,然而調(diào)用你的方法卻不一定。

調(diào)用你的方法可能本身是個(gè)事務(wù)方法(service事務(wù)方法a調(diào)用service事務(wù)方法b,也可能不是(controller調(diào)用service事務(wù)方法b  /  service非事務(wù)方法a調(diào)用service事務(wù)方法b)

然后就看傳播行為了。

Spring默認(rèn)的是PROPAGATION_REQUIRED

事務(wù)的傳播行為我們一般都是用來(lái)解決嵌套事務(wù)的,所以我們一般使用最多的是上面加黑的三種:

四、嵌套事務(wù):

嵌套事務(wù):就是事務(wù)方法A調(diào)用事務(wù)方法B,外層調(diào)用方法內(nèi)層被調(diào)用方法都是事務(wù)方法的情況。

一般我們不關(guān)心外層調(diào)用方法的事務(wù)傳播行為(用默認(rèn)的(不指定就行))。而只關(guān)心內(nèi)層被調(diào)用方法的傳播行為。

我們一般情況下,會(huì)有以下三種需求:

  1. 外層調(diào)用方法和內(nèi)層被調(diào)用方法,有異常一起回滾,沒(méi)問(wèn)題一起提交。(共用一個(gè)事務(wù))
  2. 內(nèi)層被調(diào)用方法回滾與否,不會(huì)影響外層調(diào)用方法。而外層調(diào)用方法出異?;貪L,也不會(huì)回滾內(nèi)層被調(diào)用方法(兩個(gè)獨(dú)立的事務(wù))
  3. 內(nèi)層被調(diào)用方法回滾與否,不會(huì)影響外層調(diào)用方法。而外層調(diào)用方法出異常回滾,也會(huì)回滾內(nèi)層被調(diào)用方法(嵌套事務(wù))

這三種情況正好對(duì)應(yīng)三種最常用的傳播行為

 

1----->@Transactional(propagation=Propagation.REQUIRED) :

內(nèi)外層方法共用外層方法的事務(wù)

2----->@Transactional(propagation=Propagation.REQUIRES_NEW) :

當(dāng)執(zhí)行內(nèi)層被調(diào)用方法時(shí),外層方法的事務(wù)會(huì)掛起。兩個(gè)事務(wù)相互獨(dú)立,不會(huì)相互影響。

3----->@Transactional(propagation=Propagation.NESTED) :

理解Nested的關(guān)鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區(qū)別是,PROPAGATION_REQUIRES_NEW另起一個(gè)事務(wù),將會(huì)與他的父事務(wù)相互獨(dú)立,
而Nested的事務(wù)和他的父事務(wù)是相依的,他的提交是要等和他的父事務(wù)一塊提交的。也就是說(shuō),如果父事務(wù)最后回滾,他也要回滾的。

它看起來(lái)像這樣

class ServiceA {             public void methodA() {      // 數(shù)據(jù)庫(kù)操作等其他代碼          try {            // savepoint(虛擬的)               ServiceB.methodB(); // PROPAGATION_NESTED 級(jí)別         } catch (SomeException) {                // 執(zhí)行其他業(yè)務(wù), 如ServiceC.methodC();            }      // 其他操作代碼       }     }

也就是說(shuō)ServiceB.methodB失敗回滾,那么ServiceA.methodA也會(huì)回滾到savepoint點(diǎn)上,ServiceA.methodA可以選擇另外一個(gè)分支,比如
ServiceC.methodC,繼續(xù)執(zhí)行,來(lái)嘗試完成自己的事務(wù)。
 

五、嵌套事務(wù)的使用:

關(guān)于使用我的代碼放到了我的github上了。

1、propagation=Propagation.REQUIRED的情況

內(nèi)層被調(diào)用事務(wù)方法

	@Transactional(propagation=Propagation.REQUIRED)	public void testRequired(User inner) {		testDAO.insertUser(inner);	}

外層調(diào)用方法

	@Override	//@Transactional(propagation=Propagation.REQUIRED) // 調(diào)用方法可以是事務(wù)方法也可以是非事務(wù)方法 	public void testRequired(User outer, User inner) {		testDAO.insertUser(outer);		try{			innerBean.testRequired(inner);		} catch(RuntimeException e){          log.error("內(nèi)層方法出現(xiàn)異?;貪L",e);		}	}

拋異常是通過(guò),插入的User對(duì)象的UserName重復(fù)控制的,然后觀察數(shù)據(jù)庫(kù)就可以看到相應(yīng)的情況結(jié)果。(你可以把代碼下載下來(lái)自己跑一下)

測(cè)試Main方法如下

    public static void main(String[] args) {        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");        OuterBean outerBean = (OuterBean) ctx.getBean("outerBeanImpl");        /**你能通過(guò)控制插入的數(shù)據(jù)的UserName重復(fù)產(chǎn)生異常*/        User outer = new User();        outer.setUsername("009");        outer.setName("zjl");        User inner = new User();        inner.setUsername("010");        inner.setName("zjl");        /** 選擇代碼進(jìn)行注釋,完成你想要的測(cè)試*/        outerBean.testRequired(outer, inner);        // outerBean.testRequiresNew(outer,inner);        //outerBean.testNested(outer,inner);    }

這種傳播行為能實(shí)現(xiàn):外層調(diào)用方法和內(nèi)層被調(diào)用方法,有異常一起回滾,沒(méi)問(wèn)題一起提交

2、propagation=Propagation.REQUIRES_NEW

內(nèi)層被調(diào)用事務(wù)方法

	@Override	@Transactional(propagation=Propagation.REQUIRES_NEW)	public void testRequiresNew(User inner) {		testDAO.insertUser(inner);	}

外層調(diào)用方法

	@Override	@Transactional(propagation=Propagation.REQUIRED)	public void testRequiresNew(User outer, User inner) {		testDAO.insertUser(outer);		try{			innerBean.testRequiresNew(inner);		} catch(RuntimeException e){			log.error("內(nèi)層方法出現(xiàn)異?;貪L",e);		}	}

測(cè)試方法相同

這種傳播行為能實(shí)現(xiàn):內(nèi)層被調(diào)用方法回滾與否,不會(huì)影響外層調(diào)用方法。而外層調(diào)用方法出異?;貪L,也不會(huì)回滾內(nèi)層被調(diào)用方法

3、propagation=Propagation.NESTED

內(nèi)層被調(diào)用事務(wù)方法

    @Override	@Transactional(propagation=Propagation.NESTED)	public void testNested(User inner) {		testDAO.insertUser(inner);	}

外層調(diào)用方法

	@Override	@Transactional(propagation=Propagation.REQUIRED)	public void testNested(User outer, User inner) {		testDAO.insertUser(outer);		try{			innerBean.testNested(inner);		} catch(RuntimeException e){			log.error("內(nèi)層方法出現(xiàn)異?;貪L",e);		}	}

測(cè)試方法相同

這種傳播行為能實(shí)現(xiàn):內(nèi)層被調(diào)用方法回滾與否,不會(huì)影響外層調(diào)用方法。而外層調(diào)用方法出異?;貪L,也會(huì)回滾內(nèi)層被調(diào)用方法

 

六、使用中的注意事項(xiàng):

1、外層調(diào)用內(nèi)層方法是兩個(gè)事務(wù)的都要try catch 住調(diào)用內(nèi)層方法的代碼塊。共用一個(gè)事務(wù)的不要try catch 住(要不就出下面2那個(gè)異常)。

因?yàn)镾pring聲明式事務(wù)處理是基于Aop的,默認(rèn)情況下他會(huì)在方法拋出運(yùn)行時(shí)異常時(shí),攔截異?;貪L事務(wù),然后會(huì)繼續(xù)向上拋出。 所以你要try catch 住要不外層調(diào)用方法會(huì)用相應(yīng)異常,那傳播行為就沒(méi)有用了。

	// 就類似這種    @Override	@Transactional(propagation=Propagation.REQUIRED)	public void testNested(User outer, User inner) {		testDAO.insertUser(outer);		try{			innerBean.testNested(inner);		} catch(RuntimeException e){			log.error("內(nèi)層方法出現(xiàn)異?;貪L",e);		}	}

 

2、“Transaction rolled back because it has been marked as rollback-only ”異常的出現(xiàn)

出現(xiàn)場(chǎng)景:這種異常一般是在,嵌套事務(wù)使用中,內(nèi)層事務(wù)使用默認(rèn)的事務(wù)傳播行為(Propagation.REQUIRED),內(nèi)外共用一個(gè)事務(wù)時(shí),外層方法把內(nèi)層方法try catch 住了,就會(huì)出現(xiàn)。

原因:內(nèi)層方法出異常了,會(huì)向上拋異常,SpringAOP攔截到,就會(huì)把事務(wù)標(biāo)志為rollback only,就是準(zhǔn)備要回滾。

由于內(nèi)外方法共用一個(gè)事務(wù),這時(shí)要是外層方法把這個(gè)異常捕獲了,外層方法就繼續(xù)提交。但是事務(wù)標(biāo)記已經(jīng)置了,那就會(huì)拋這個(gè)異常。

 

3、同一的類的事務(wù)方法是無(wú)法直接調(diào)用的,如果 ServiceA.methodA調(diào)用 Service.methodB,會(huì)使被調(diào)用方法的事務(wù)失效

因?yàn)閟pring的事務(wù)是基于代理類來(lái)實(shí)現(xiàn)的。在controller里的service其實(shí)是代理對(duì)象,所以b方法的事務(wù)有效。,而在同一個(gè)類中ServiceA.methodA調(diào)用 Service.methodB,你拿到的不是代理后的methodB,所以事務(wù)會(huì)失效
解決方法很簡(jiǎn)單,在methodA方法類中獲取當(dāng)前對(duì)象的代理對(duì)象

ServiceA proxy =(ServiceA)AopContext.currentProxy();proxy.b();

 

 

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
解惑 spring 嵌套事務(wù)
spring事務(wù)傳播屬性和隔離級(jí)別
Spring 雙層事務(wù),我拋出的異常去哪了?
說(shuō)說(shuō)Python中閉包是什么?
Spring聲明式事務(wù)管理源碼解讀之事務(wù)提交
Spring聲明式事務(wù)管理源碼解讀之事務(wù)提交(轉(zhuǎn)載)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服