久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

事務(wù)的傳播行為&&嵌套事務(wù)的使用

 liang1234_ 2019-02-21

一,、前言:

事務(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)用方法出異常回滾,,也不會(huì)回滾內(nèi)層被調(diào)用方法(兩個(gè)獨(dú)立的事務(wù))
  3. 內(nèi)層被調(diào)用方法回滾與否,,不會(huì)影響外層調(diào)用方法。而外層調(diào)用方法出異?;貪L,,也會(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)異常回滾",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)行注釋?zhuān)瓿赡阆胍臏y(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)有用了,。

	// 就類(lè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)異常回滾",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、同一的類(lèi)的事務(wù)方法是無(wú)法直接調(diào)用的,,如果 ServiceA.methodA調(diào)用 Service.methodB,會(huì)使被調(diào)用方法的事務(wù)失效

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

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

 

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多