久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    事務的傳播行為&&嵌套事務的使用

     liang1234_ 2019-02-21

    一、前言:

    事務的傳播行為(propagation)就是為了解決外層方法調用內層事務方法的各個情況的。

    接下來要說的嵌套事務的使用是基于Spring聲明式事務管理中的注解@Transactional 方式的。

    二、事務的傳播行為:

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

     

    三、關于事務傳播行為:

    傳播行為就是一個約定:“別的方法調用自己的時候會以怎樣的方式開啟事務”。

    當你給一個方法指定傳播行為的時候這時這個方法本身肯定是支持事務的方法,然而調用你的方法卻不一定。

    調用你的方法可能本身是個事務方法(service事務方法a調用service事務方法b,也可能不是(controller調用service事務方法b  /  service非事務方法a調用service事務方法b)

    然后就看傳播行為了。

    Spring默認的是PROPAGATION_REQUIRED

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

    四、嵌套事務:

    嵌套事務:就是事務方法A調用事務方法B,外層調用方法內層被調用方法都是事務方法的情況。

    一般我們不關心外層調用方法的事務傳播行為(用默認的(不指定就行))。而只關心內層被調用方法的傳播行為。

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

    1. 外層調用方法和內層被調用方法,有異常一起回滾,沒問題一起提交。(共用一個事務)
    2. 內層被調用方法回滾與否,不會影響外層調用方法。而外層調用方法出異常回滾,也不會回滾內層被調用方法(兩個獨立的事務)
    3. 內層被調用方法回滾與否,不會影響外層調用方法。而外層調用方法出異常回滾,也會回滾內層被調用方法(嵌套事務)

    這三種情況正好對應三種最常用的傳播行為

     

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

    內外層方法共用外層方法的事務

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

    當執行內層被調用方法時,外層方法的事務會掛起。兩個事務相互獨立,不會相互影響。

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

    理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
    而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最后回滾,他也要回滾的。

    它看起來像這樣

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

    也就是說ServiceB.methodB失敗回滾,那么ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
    ServiceC.methodC,繼續執行,來嘗試完成自己的事務。
     

    五、嵌套事務的使用:

    關于使用我的代碼放到了我的github上了。

    1、propagation=Propagation.REQUIRED的情況

    內層被調用事務方法

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

    外層調用方法

    	@Override
    	//@Transactional(propagation=Propagation.REQUIRED) // 調用方法可以是事務方法也可以是非事務方法 
    	public void testRequired(User outer, User inner) {
    		testDAO.insertUser(outer);
    		try{
    			innerBean.testRequired(inner);
    		} catch(RuntimeException e){
              log.error("內層方法出現異常回滾",e);
    		}
    	}

    拋異常是通過,插入的User對象的UserName重復控制的,然后觀察數據庫就可以看到相應的情況結果。(你可以把代碼下載下來自己跑一下)

    測試Main方法如下

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

    這種傳播行為能實現:外層調用方法和內層被調用方法,有異常一起回滾,沒問題一起提交

    2、propagation=Propagation.REQUIRES_NEW

    內層被調用事務方法

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

    外層調用方法

    	@Override
    	@Transactional(propagation=Propagation.REQUIRED)
    	public void testRequiresNew(User outer, User inner) {
    		testDAO.insertUser(outer);
    		try{
    			innerBean.testRequiresNew(inner);
    		} catch(RuntimeException e){
    			log.error("內層方法出現異常回滾",e);
    		}
    	}

    測試方法相同

    這種傳播行為能實現:內層被調用方法回滾與否,不會影響外層調用方法。而外層調用方法出異常回滾,也不會回滾內層被調用方法

    3、propagation=Propagation.NESTED

    內層被調用事務方法

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

    外層調用方法

    	@Override
    	@Transactional(propagation=Propagation.REQUIRED)
    	public void testNested(User outer, User inner) {
    		testDAO.insertUser(outer);
    		try{
    			innerBean.testNested(inner);
    		} catch(RuntimeException e){
    			log.error("內層方法出現異常回滾",e);
    		}
    	}

    測試方法相同

    這種傳播行為能實現:內層被調用方法回滾與否,不會影響外層調用方法。而外層調用方法出異常回滾,也會回滾內層被調用方法

     

    六、使用中的注意事項:

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

    因為Spring聲明式事務處理是基于Aop的,默認情況下他會在方法拋出運行時異常時,攔截異常回滾事務,然后會繼續向上拋出。 所以你要try catch 住要不外層調用方法會用相應異常,那傳播行為就沒有用了。

    	// 就類似這種
        @Override
    	@Transactional(propagation=Propagation.REQUIRED)
    	public void testNested(User outer, User inner) {
    		testDAO.insertUser(outer);
    		try{
    			innerBean.testNested(inner);
    		} catch(RuntimeException e){
    			log.error("內層方法出現異常回滾",e);
    		}
    	}

     

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

    出現場景:這種異常一般是在,嵌套事務使用中,內層事務使用默認的事務傳播行為(Propagation.REQUIRED),內外共用一個事務時,外層方法把內層方法try catch 住了,就會出現。

    原因:內層方法出異常了,會向上拋異常,SpringAOP攔截到,就會把事務標志為rollback only,就是準備要回滾。

    由于內外方法共用一個事務,這時要是外層方法把這個異常捕獲了,外層方法就繼續提交。但是事務標記已經置了,那就會拋這個異常。

     

    3、同一的類的事務方法是無法直接調用的,如果 ServiceA.methodA調用 Service.methodB,會使被調用方法的事務失效

    因為spring的事務是基于代理類來實現的。在controller里的service其實是代理對象,所以b方法的事務有效。,而在同一個類中ServiceA.methodA調用 Service.methodB,你拿到的不是代理后的methodB,所以事務會失效
    解決方法很簡單,在methodA方法類中獲取當前對象的代理對象

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

     

     

      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 亚洲国产精品无码中文LV| 亚洲A成人片在线播放| 成午夜精品一区二区三区| 国产精品午夜福利资源| 国产美女MM131爽爽爽| 亚洲国产成人无码网站| 伊人久久大香线蕉AV网禁呦| 熟妇人妻中文字幕| 在线看无码的免费网站| 亚洲AV无码一区二区三区在线播放| 东方四虎av在线观看| 四虎国产精品成人| 中文字幕日韩精品国产| 国产午夜精品一区理论片| 精品国产中文字幕av| 成码无人AV片在线电影网站| 忘忧草在线社区www中国中文| 精品 日韩 国产 欧美 视频 | 久久久久亚洲AV成人网人人网站| 潮喷失禁大喷水无码| 亚洲AV永久纯肉无码精品动漫| 又爽又黄又无遮掩的免费视频 | 欧洲免费一区二区三区视频| 97久久天天综合色天天综合色HD| 国产在线午夜不卡精品影院| 人妻无码久久中文字幕专区| 欧美肥老太牲交大战| 国产成人人综合亚洲欧美丁香花| 国内揄拍国内精品人妻| 丁香婷婷色综合激情五月| 久久精品国产99久久久古代 | 无码精品人妻一区二区三区影院| 又湿又紧又大又爽A视频男| 亚洲人成无码网站18禁| 日本高清无卡码一区二区| 中文字幕在线国产精品| 日日碰狠狠添天天爽无码| 亚洲AV午夜成人无码电影| 国产99视频精品免费视频36| 色8激情欧美成人久久综合电影| 丰满的少妇被猛烈进入白浆|