1. 程式人生 > >Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景(贊)

Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景(贊)

 摘要: 在工作中時常需要用到Spring的事務,每次遇到問題都google十分浪費時間,不妨自己總結一下做個記錄,希望以後遇到問題的時候能在自己的記錄中找到解答。:)
超過了字數限制,強行被分割。。。。



三、Spring事務的傳播性與隔離級別

    Spring它對JDBC的隔離級別作出了補充和擴充套件,其提供了7種事務傳播行為。(通俗解釋原址)

    1、PROPAGATION_REQUIRED:預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務。適合絕大多數情況。

    2、PROPAGATION_REQUIRES_NEW:如果沒有,就新建一個事務;如果有,就將當前事務掛起。

    3、PROPAGATION_NESTED:如果沒有,就新建一個事務;如果有,就在當前事務中巢狀其他事務。

    4、PROPAGATION_SUPPORTS:如果沒有,就以非事務方式執行;如果有,就使用當前事務。

    5、PROPAGATION_NOT_SUPPORTED:如果沒有,就以非事務方式執行;如果有,就將當前事務掛起。即無論如何不支援事務。

    6、PROPAGATION_NEVER:如果沒有,就以非事務方式執行;如果有,就丟擲異常。

    7、PROPAGATION_MANDATORY:如果沒有,就丟擲異常;如果有,就使用當前事務。

    第4、5、6、7種特性很好理解了,主要是前三種特性比較容易混淆或用錯。

    那麼PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED的區別在哪呢?

    什麼有就建立一個什麼巢狀掛起,很明顯不如一些使用場景清晰,那就直接上例子。

    先定義一些實驗性的方法。(例子程式碼:https://git.oschina.net/sluggarddd/spring-tx-demo.git)

@Service
public class IUserServiceImpl implements IUserService {

    @Resource
    IUserDAO userDAO;

    @Resource
    IUserService2 userService2;

    //不帶事務的方法
    public void funNone() throws Exception {
        save(new UserEntity("zhw"));

    }


    //啟動預設事務的方法
    @Transactional(propagation = Propagation.REQUIRED)
    public void funRequire() throws Exception {
        save(new UserEntity("wlj"));

    }

    //啟動預設事務的方法
    @Transactional(propagation = Propagation.REQUIRED)
    public void funRequire2() throws Exception {
        save(new UserEntity("shifang"));

    }

    //啟動預設事務的方法,丟擲RuntimeException
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void funRequireException() throws Exception {
        save(new UserEntity("max"));

        throwExcp();

    }

    //啟動巢狀事務的方法
    @Transactional(propagation = Propagation.NESTED)
    public void funNest() throws Exception {
        save(new UserEntity("yunxinghe"));

    }


    //啟動巢狀事務的方法,但會丟擲異常
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void funNestException() throws Exception {
        save(new UserEntity("edward"));
        throwExcp();
    }

    //REQUIRES_NEW事務的方法
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void funRequireNew() throws Exception {
        save(new UserEntity("kb"));

    }

    //REQUIRES_NEW事務的方法,但會丟擲異常
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void funRequireNewException() throws Exception {
        save(new UserEntity("laura"));
        throwExcp();
    }


    //丟擲異常
    private void throwExcp() throws Exception {
        throw new RuntimeException("boom");
    }

    //儲存資料
    public int save(UserEntity userEntity) throws Exception {
        userDAO.save(userEntity);
        return userEntity.getId();
    }
}
    我們定義了兩個映象(就是一樣的Serivce)分別是UserService,UserService2,是一樣的,只是相互呼叫,不重複上程式碼。

    

@Override
@Transactional
public void fun1() throws Exception {

    //資料庫操作
    funNone();
    //呼叫另一個service的方法
    userService2.funNest();

    //當呼叫另一個Service的method的時候,想要將他的事務加到現在這個事務中,很可能自然而然想到了巢狀
    //這麼想就錯了,Required的定義裡已經說明了如果沒有,就新建一個事務;如果有,就加入當前事務。
    //那麼直接使用Required就滿足需求
    //這樣在方法中任何地方發生unchecked異常將觸發整個方法的回滾
    //而Nested的使用場景下面再介紹

}
    NESTED事務使用場景

@Override
@Transactional
public void fun2() throws Exception {
    //巢狀事務的使用場景
    funNone();

    try {
        //當所呼叫的方法為NESTED事務,該事務的回滾可以不影響到呼叫者的事務
        //當然如果沒有catch exception,異常冒泡而出,就將觸發呼叫者事務的回滾
        userService2.funNestException();
    } catch (Exception e) {

        //do something
    }

    userService2.funRequire();


}

//執行結果:
//userService2.funNestException()被回滾
//其他插入成功
    外部的異常能觸發所呼叫的NESTED事務回滾

@Override
@Transactional
public void fun3() throws Exception {


    //巢狀事務的使用場景
    funNone();
    try {
        //呼叫的事務為NESTED事務的方法
        userService2.funNest();
    } catch (Exception e) {

        //do something
    }

    userService2.funRequire();

    //此時在呼叫者處,觸發一個unchecked異常
    throwExcp();


    //此時會發現包括呼叫的userService2.funNest()也被回滾了
    //也就是說,當呼叫的方法是NESTED事務,該方法丟擲異常如果得到了處理(try-catch),那麼該方法發生異常不會觸發整個方法的回滾
    //而呼叫者出現unchecked異常,卻能觸發所呼叫的nested事務的回滾.
}

//執行結果
//全部被回滾
    REQUIRES_NEW的使用場景

@Override
@Transactional
public void fun4() throws Exception {
    //而REQUIRES_NEW,當被呼叫時,就相當於暫停(掛起)當前事務,先開一個新的事務去執行REQUIRES_NEW的方法,如果REQUIRES_NEW中的異常得到了處理
    //那麼他將不影響呼叫者的事務,同時,呼叫者之後出現了異常,同樣也不會影響之前呼叫的REQUIRES_NEW方法的事務.


    //不會回滾
    funNone();
    try {
        //當異常得到處理,外部不會觸發回滾
        userService2.funRequireNewException();
    } catch (Exception e) {

    }
}

//執行結果
//funNone()正常持久化
// userService2.funRequireNewException()回滾
@Override
@Transactional
public void fun5() throws Exception {


    //資料庫操作
    funNone();
    //呼叫RequireNew型別事務的方法,呼叫者的異常回滾不會影響到它
    userService2.funRequireNew();
    //資料庫操作
    funNone();

    //丟擲unchecked異常,觸發回滾
    throwExcp();


}

//執行結果
//userService2.funRequireNew();正常持久化
//其他操作被回滾
如果呼叫的是REQUIRED型別,即使處理了被呼叫方法丟擲的異常仍然會被回滾。

@Override
@Transactional
public void fun6() throws Exception {

    funNone();

    try {
        //當呼叫的是Required時,就算異常被處理了,整個方法也將會回滾
        userService2.funRequireException();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

//執行結果
//被回滾
    總結:附上一段我覺得很好的總結(Jurgen Hoeller原話翻譯)(翻譯從這裡拷的)

    PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被完全 commited 或 rolled back 而不依賴於外部事務, 它擁有自己的隔離範圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. 
     另一方面, PROPAGATION_NESTED 開始一個 "巢狀的" 事務,  它是已經存在事務的一個真正的子事務. 潛套事務開始執行時,  它將取得一個 savepoint. 如果這個巢狀事務失敗, 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它才會被提交. 
    由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 完全是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 潛套事務也會被 commit, 這個規則同樣適用於 roll back. 
    
    

四、Spring事務自我呼叫的坑

    當Spring的事務在同一個類時,它的自我呼叫時事務就完犢子了!(不知道這個的時候被坑出翔)

    當同一個類的方法之間事務發生自我呼叫,其事務的特性將失效。

    

@Override
@Transactional
public void fun7() throws Exception {

    funRequire();

    try {
        //本應回滾這個方法,但發生了異常並沒有回滾
        funNestException();
    } catch (Exception e) {
        System.out.println(e.getMessage());

    }

    funRequire();

}
    例如上面Nested的特性就沒了,其執行結果是三個發生insert的語句都成功插入到資料庫了。

    原因我自己肯定沒別人總結的好(連問題都說的不太清楚),就直接放連結了(原因點此),不想看的直接上解決方法。

    1、首先引入

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}<ersion>
</dependency>
    2、開啟暴露AOP代理到ThreadLocal支援

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
    3、在自我呼叫的時候這麼寫

fun8() Exception {
    ((IUserService) AopContext.()).funRequire();

    {
        ((IUserService) AopContext.()).funNestException();
    } (Exception e) {
        System..println(e.getMessage());

    }

    ((IUserService) AopContext.()).funRequire();
}
    這樣,就能讓配置在該方法上的事務發揮應有的特性啦。

    原因我也來總結一句,因為開啟事務和事務回滾,實際這個過程是aop代理幫忙完成的,當呼叫一個方法時,他會先檢查時候有事務,有則開啟事務,當呼叫本類的方法是,他並沒有將其視為proxy呼叫,而是方法的直接呼叫,所以也就沒有檢查該方法是否含有事務這個過程,那麼他生命的事務也就不成立了。

    另外,除了這個解決方法,開濤大神那個部落格還提供了其他解決方式,可以根據自己的需求選擇。





    總結一下對自己理解還是蠻有幫助的,希望也能稍微幫到有需要的人。

    完。 

相關推薦

spring事務傳播行為 Spring事務總結---傳播級別以及REQUIRED_NEWNESTED的使用場景()

總結:附上一段我覺得很好的總結(Jurgen Hoeller原話翻譯)(翻譯從這裡拷的)     PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這

Spring事務總結---傳播級別以及REQUIRED_NEWNESTED的使用場景

三、Spring事務的傳播性與隔離級別     Spring它對JDBC的隔離級別作出了補充和擴充套件,其提供了7種事務傳播行為。(通俗解釋原址)     1、PROPAGATION_REQUIRED:預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務。適合絕大

Spring事務總結---傳播級別以及REQUIRED_NEWNESTED的使用場景()

 摘要: 在工作中時常需要用到Spring的事務,每次遇到問題都google十分浪費時間,不妨自己總結一下做個記錄,希望以後遇到問題的時候能在自己的記錄中找到解答。:) 超過了字數限制,強行被分割。。。。 三、Spring事務的傳播性與隔離級別     Spring它對JDB

Spring事務傳播級別

### 一、簡單說明 傳播屬性|描述 -|- PROPAGATION_REQUIRED|如果當前沒有事務,就建立一個事務,如果當前存在事務,就加入該事務。 PROPAGATION_REQUIRED_NEW|當前的方法必須啟動新事務,並在它自己的事務內執行,不管是否存著事務,都開啟新事務。 PROPAGATIO

spring事務傳播屬性和事務隔離級別配置事務(註解方式)

一、Propagation (事務的傳播屬性) Propagation :  key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用:   PROPAGATION_REQUIRED--支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。 PROPAG

Java知識點集合05--- Spring的兩大核心&Spring事務傳播特性&隔離級別&ORM&ibatis和Hibernate&Hibernate對映物件狀態

Spring的兩大核心 spring是J2EE應用程式框架,是輕量級的IOC和AOP容器框架(相對於EJB ),針對javabean生命週期進行管理的親兩級容器。 IOC(控制反轉Invesion of control)或DI(依賴注入 Dependency

Spring事務傳播特性和隔離級別(持續更新中)

Spring TransactionDefinition介面中定義了事務的隔離級別和事務的傳播特性 傳播特性 例子: class ClassA{ method(){ //邏輯處理1 classB.

spring事務五大隔離級別、七大傳播行為

1.事務的定義:事務是指多個操作單元組成的合集,多個單元操作是整體不可分割的,要麼都操作不成功,要麼都成功。其必須遵循四個原則(ACID)。 原子性(Atomicity):即事務是不可分割的最小工作單元,事務內的操作要麼全做,要麼全不做;一致性(Consistency):

Spring 事務管理 事務傳播級別

例子:對於預設的傳播級別 REQUIRED 的測試首先對於 REQUIRED 的解釋如下: 預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務,也就是大家都使用同一個事務模型,只要有一個發生了異常,那麼整個事務都會回滾。其中對於發生異常導致事務回滾需要注重理解,否

Spring事務傳播行為、隔離級別、回滾、只讀和過期

事務的傳播性- 當事務的方法被另一個事務的方法呼叫時,必須指定事務應該如何傳播。如:方法可能繼續在現有的事務中執行,也可能開啟一個新的事務,並在自己的事務中執行。- 事務的傳播行為可以由傳播屬性指定。Spring定義了7種傳播行為:required:如果有事務在執行,當前的方

Spring 事務的隔離級別傳播行為的理解

一、Spring 事務的隔離級別 在瞭解Spring事務隔離級別前,先弄清楚以下概念: 髒讀:髒讀發生在一個事務讀取了被另一個事務改寫但還未提交的資料時。如果這些改變在稍後被回滾,那麼之前的事務讀取的到資料就是無效的。 不可重複讀:不

事務傳播無效,required_new無效,動態代理給spring事務傳播留下的坑

事務的傳播級別 七種傳播級別 propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇。(預設) propagation_supports:支援當前事務,如果沒有當前事務,就以

Spring事務配置的五種方式事務傳播相關(不看後悔,一看必懂!)

原文:http://blog.csdn.net/hjm4702192/article/details/17277669 前段時間對Spring的事務配置做了比較深入的研究,在此之間對Spring的事務配置雖說也配置過,但是一直沒有一個清楚的認識。通過這次的學習發覺Sprin

Spring事務總結---事務概述Spring事務的基本使用(完整)

 一、事務概述    這一節內容純粹是為了寫而寫的,權當溫習資料庫知識和熟悉下怎麼寫部落格了,誰讓自己菜呢。:)    看了許多別的部落格和資料,事務兩個字都快不認識了,那麼其實事務的概念很簡單,可以理解為一件事情,在計算機裡,它就是一個操作序列。    它相比於普通的事情不同的是,它必須服從ISO/IEC指

通過TransactionDefinition介面來學習spring事務的隔離級別傳播特性(4.3.4版本)

通過spring官方包中帶的原始碼來看spring的事務的5中隔離級別和7種傳播特性;     原始碼如下: /* * Copyright 2002-2015 the original author or authors. * * Licensed under th

spring 事務傳播特性

nal 調用 ransac 提交 port 文件 action com pre 1.聲明式事物中,一個類serviceA的方法test1()調用另一個類serviceB的方法test2() 要是serviceB的test2()事務配置在xml文件中為REQUIRED,又

spring事務的隔離級別(透徹理解)

wired pan 用戶 出現 不同的 而且 之前 () b- 1.spring 事務這個東西,是輪子,每個service,都需要用到。所以幹脆就做在框架層實現。 2.spring是怎麽給你的service方法加事務的呢?jdk動態代理,會針對每個service類裏

Spring事務的隔離級別

多次 結果 結束 說明 div edit 對數 正在 gb2312 1. ISOLATION_DEFAULT: 這是一個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別. 另外四個與 JDBC的隔離級別相對

Spring事務處理的實現:Spring事務總結

這篇我想對Spring事務機制進行一次總結,總結的方式也和AOP類似那就是使用圖解的方式。首先我們需要對我們事務的AOP機制進行初始化,也就是宣告要對那些方法(切面)進行增強,這裡涉及到了TransactionInterceptor攔截器鏈的生成。 接著書上講述了事務處理配置的讀入。

spring 事務的隔離級別

spring有五大隔離級別: ISOLATION_DEFAULT:用底層資料庫的預設隔離級別,資料庫管理員設定什麼就是什麼 ISOLATION_READ_UNCOMMITTED(未提交讀):最低隔離級別、事務未提交前,就可被其他事務讀取(會出現幻讀、髒讀、不可重複讀) ISOLA