最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring七大事務傳遞機制深入分析實現(xiàn)原理

 更新時間:2023年03月27日 09:07:50   作者:一路向陽向北  
實際項目開發(fā)中,如果涉及到多張表操作時,為了保證業(yè)務數據的一致性,大家一般都會采用事務機制,好多小伙伴可能只是簡單了解一下,遇到事務失效的情況,便會無從下手,下面這篇文章主要給大家介紹了關于Spring事務傳遞機制的相關資料,需要的朋友可以參考下

Spring事務傳遞機制原理

首先,我們通過org.springframework.transaction.annotation.Propagation來了解一下spring事務的傳播定義:

1. REQUIRED(默認):

Support a current transaction, create a new one if none exists.

支持當前事務,如果沒有則創(chuàng)建一個新的

2. SUPPORTS

Support a current transaction, execute non-transactionally if none exists.

支持當前事務,如果沒有則不使用事務

3. MANDATORY

Support a current transaction, throw an exception if none exists

支持當前事務,如果沒有事務則報錯

4. REQUIRED_NEW

Create a new transaction, and suspend the current transaction if one exists.

新建一個事務,同時將當前事務掛起

5. NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists

以無事務的方式執(zhí)行,如果當前有事務則將其掛起

6. NEVER

Execute non-transactionally, throw an exception if a transaction exists.

以無事務的方式執(zhí)行,如果當前有事務則報錯

7. NESTED

Execute within a nested transaction if a current transaction exists,behave like PROPAGATION_REQUIRED else

如果當前有事務,則在當前事務內部嵌套一個事務,內部事務的回滾不影響當前事務。如果當前沒有事務,就相當于REQUIRED

Note: Actual creation of a nested transaction will only work on specific transaction managers. Out of the box, this only applies to

the JDBC DataSourceTransactionManager when working on a JDBC 3.0 driver.

Some JTA providers might support nested transactions as well.

注意:該定義只能在JDBC3.0驅動下的DataSourceTransactionManager事務管理器中使用,有些JTA事務可能也會支持

接下來我們通過代碼驗證一下spring事務的傳遞性,在UserServiceImpl類添加兩個方法如下:

@Transactional(propagation = Propagation.NEVER)
public User findById(Long id) {
    User user =  userMapper.findById(id);
    System.out.println("find user:"+user);
    return user;
}
@Transactional
public void transactionTest(int t) {
    findById(t+0L);
}

我們調用transactionTest方法,transactionTest沒有配置Propagation,所以默認是REQUIRED,會在當前新建一個事務。transactionTest內部調用findById,由于findById事務傳播定義為NEVER,表明它當前不能有事務,按理說這里會拋出異常,但是我們利用junit執(zhí)行后發(fā)現(xiàn),transactionTest是可以正常執(zhí)行的。

事實上,如果使用@Transaction方法里嵌套調用的是同一個類的方法,spring代理會忽略嵌套方法的@Transaction配置。但是,如果是其他注入對象的方法,那么@Transaction配置就會生效。我們將上面的transactionTest方法的事務傳播定義為NERVER,并新增一個insert操作,即使insert啟用了事務并且拋出異常,但是事務不會生效,也不會有回滾的說法,程序會拋出異常但是數據會保存到數據庫中:

@Transactional(propagation = Propagation.NEVER)
public void transactionTest(int t) {
    findById(t+0L);
    insertUser("huangxl","abc123");
}
@Transactional
public int insertUser(String name, String password) {
    User user = new User();
    user.setPassword(password);
    user.setUsername(name);
    int insertCount =  userMapper.insertEntity(user);
    if(insertCount == 1 ){
        throw new RuntimeException("test transaction roll back");
    }
    return insertCount;
}

接下來我們來測試不同類之間的方法(事務)調用,以下的測試都是基于junit執(zhí)行TransactionTestServiceImpl.test()方法

一、Propagation.NERVER的測試

下面我們將UserService注入到TransactionTestServiceImpl中,test方法使用@Transactional,UserService findById事務傳播定義不變,還是NERVER。

UserserviceImpl:
@Service
public class TransactionTestServiceImpl implements TransactionTestService {
    @Autowired
    private UserService userService;
    @Override
    @Transactional
    public void test() {
        userService.findById(1L);
    }
}
TransactionTestServiceImpl:
@Service
public class UserServiceImpl implements UserService {
    @Override
    @Transactional(propagation = Propagation.NEVER)
    public User findById(Long id) {
        User user =  userMapper.findById(id);
        System.out.println("find user:"+user);
        return user;
    }
}

由于test默認啟用了事務,findById不允許當前有事務,所以我們執(zhí)行test方法后會發(fā)現(xiàn)程序拋出了異常:

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’

結論:

NERVER 不允許當前存在事務

二、Propagation.REQUIRED的測試

UserserviceImpl:
@Transactional
public int insertUser(String name, String password) {
    User user = new User();
    user.setPassword(password);
    user.setUsername(name);
    int insertCount =  userMapper.insertEntity(user);
    if(insertCount == 1 ){
        throw new RuntimeException("test transaction roll back");
    }
    return insertCount;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    try {
        userService.insertUser("abc", "123");
    } catch (Exception e) {
        //do Nothing
    }
    userMapper.updateUserPassWord(1L, "456");
}

我們會發(fā)現(xiàn),即使捕獲了userService.insertUser拋出的異常,test還是把insertUser和updateUserPassword操作當成是一個整體,整個事務還是回滾了,程序拋出了下面的異常:

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

結論:

REQUIRED子事務會影響當前事務的提交、回滾

三、Propagation.NESTED的測試

UserserviceImpl:
@Transactional(propagation = Propagation.NESTED)
public int insertUser(String name, String password) {
    User user = new User();
    user.setPassword(password);
    user.setUsername(name);
    int insertCount =  userMapper.insertEntity(user);
    if(insertCount == 1 ){
        throw new RuntimeException("test transaction roll back");
    }
    return insertCount;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    try {
        userService.insertUser("abc", "123");
    } catch (Exception e) {
        //do Nothing
    }
    userMapper.updateUserPassWord(1L, "456");
}

程序正常運行,因為NESTED內部事務回滾不影響外部事務。假如這個時候我們把test的@Transactional去掉再運行test方法,發(fā)現(xiàn)insertUser沒有插入用戶信息,說明當前沒有事務的情況下,NESTED會默認創(chuàng)建一個事務,類似于REQUIRED。

如果我們把程序改為下面的情況:

UserserviceImpl:
@Transactional(propagation = Propagation.NESTED)
public int insertUser(String name, String password) {
    User user = new User();
    user.setPassword(password);
    user.setUsername(name);
    int insertCount =  userMapper.insertEntity(user);
    return insertCount;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    userService.insertUser("abc", "123");
    int updateRow = userMapper.updateUserPassWord(1L, "456");
    if (updateRow == 1) {
        throw new RuntimeException("transational roll back");
    }
}

我們會發(fā)現(xiàn)沒有插入用戶信息,當前事務和子事務全部回滾。

結論:

NESTED子事務回滾不會影響當前事務的提交(catch回滾異常的情況下),但是當前事務回滾會回滾子事務。也就是說只有當前事務提交成功了,子事務才會提交成功。

四、Propagation.REQUIRED_NEW的測試

UserserviceImpl:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insertUser(String name, String password) {
    User user = new User();
    user.setPassword(password);
    user.setUsername(name);
    int insertCount =  userMapper.insertEntity(user);
    return insertCount;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    userService.insertUser("abc", "123");
    int updateRow = userMapper.updateUserPassWord(1L, "456");
    if (updateRow == 1) {
        throw new RuntimeException("transational roll back");
    }
}

運行結果:程序報錯,但是有用戶信息插入。

將程序改為下面的樣子:

UserserviceImpl:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int updateUserPassWorld(Long id, String password) {
    int update =  userMapper.updateUserPassWord(id,password);
    return update;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    //當前事務
    userMapper.updateUserPassWord(28L, "123456");
    //執(zhí)行REQUIRES_NEW事務
    userService.updateUserPassWorld(28L, "000000");
   System.out.println("commit");
}

執(zhí)行程序,發(fā)現(xiàn)程序遲遲沒有打印字符串commit,發(fā)生了死鎖。

結論:

REQUIRES_NEW會啟用一個新的事務,事務擁有完全獨立的能力,它不依賴于當前事務,執(zhí)行時會掛起當前事務,直到REQUIRES_NEW事務完成提交后才會提交當前事務,如果當前事務與REQUIRES_NEW 存在鎖競爭,會導致死鎖。

五、NOT_SUPPORTED的測試

UserserviceImpl:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public int updateUserPassWorld(Long id, String password) {
    int updateRow =  userMapper.updateUserPassWord(id,password);
if(updateRow ==1 ){
    throw new RuntimeException("roll back test");
}
return updateRow;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    userService.updateUserPassWorld(28L, "000000");
}

程序運行報錯,但是id為28的用戶密碼還是更新了。

將程序改為下面這個情況:

UserserviceImpl:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public int updateUserPassWorld(Long id, String password) {
    int update =  userMapper.updateUserPassWord(id,password);
    return update;
}
TransactionTestServiceImpl:
@Transactional
public void test() {
    //當前事務
    userMapper.updateUserPassWord(28L, "123456");
    //執(zhí)行REQUIRES_NEW事務
    userService.updateUserPassWorld(28L, "000000");
   System.out.println("commit");
}

執(zhí)行程序,發(fā)現(xiàn)程序遲遲沒有打印字符串commit,發(fā)生了死鎖。

結論:

NOT_SUPPORTED會掛起當前事務,并且NOT_SUPPORTED定義的方法內部不啟用顯示事務,如果NOT_SUPPORTED和當前事務存在鎖競爭,會發(fā)生死鎖。

六、NOT_SUPPORTED的測試

UserserviceImpl:
@Transactional(propagation = Propagation.MANDATORY)
public int updateUserPassWorld(Long id, String password) {
    int updateRow =  userMapper.updateUserPassWord(id,password);
    return updateRow;
}
TransactionTestServiceImpl:
public void test() {
    userService.updateUserPassWorld(28L, "123456");
}

程序運行錯誤:

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’

結論:

MANDATORY必須包含在事務中,如果事務不存在,則拋出異常

到此這篇關于Spring七大事務傳遞機制深入分析實現(xiàn)原理的文章就介紹到這了,更多相關Spring事務傳遞機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java中不用第三個變量來互換兩個變量的值

    Java中不用第三個變量來互換兩個變量的值

    在程序運行期間,隨時可能產生一些臨時數據,應用程序會將這些數據保存在一些內存單元中,每個內存單元都用一個標識符來標識。這些內存單元被稱為變量,定義的標識符就是變量名,內存單元中存儲的數據就是變量的值
    2021-10-10
  • MyBatis標簽之Select?resultType和resultMap詳解

    MyBatis標簽之Select?resultType和resultMap詳解

    這篇文章主要介紹了MyBatis標簽之Select?resultType和resultMap,在MyBatis中有一個ResultMap標簽,它是為了映射select標簽查詢出來的結果集,下面使用一個簡單的例子,來介紹 resultMap 的使用方法,需要的朋友可以參考下
    2022-09-09
  • Jmeter壓力測試簡單教程(包括服務器狀態(tài)監(jiān)控)

    Jmeter壓力測試簡單教程(包括服務器狀態(tài)監(jiān)控)

    Jmeter是一個非常好用的壓力測試工具。Jmeter用來做輕量級的壓力測試,非常合適,本文詳細的介紹了Jmeter的使用,感性的可以了解一下
    2021-11-11
  • MyBatis超詳細講解如何實現(xiàn)分頁功能

    MyBatis超詳細講解如何實現(xiàn)分頁功能

    MyBatis-Plus?是一個?Mybatis?增強版工具,在?MyBatis?上擴充了其他功能沒有改變其基本功能,為了簡化開發(fā)提交效率而存在,本篇文章帶用它實現(xiàn)分頁功能
    2022-03-03
  • Java中的引用類型和使用場景詳細

    Java中的引用類型和使用場景詳細

    這篇文章介紹的是Java中的引用類型和使用場景,主要內容展開Java中的引用類型,有強引用、軟引用 、弱引用、虛引用,需要的朋友可以參考一下
    2021-10-10
  • Java FutureTask類使用案例解析

    Java FutureTask類使用案例解析

    這篇文章主要介紹了Java FutureTask類使用案例解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值析,需要的朋友可以參考下
    2020-04-04
  • Java中接口的深入詳解

    Java中接口的深入詳解

    在Java語言中,接口由類來實現(xiàn)以便使用接口中的方法,這篇文章主要給大家介紹了關于Java中接口的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-11-11
  • Java String類的常用方法匯總

    Java String類的常用方法匯總

    這篇文章主要為大家詳細匯總了Java String類的常用方法,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Java中面向對象的知識點總結

    Java中面向對象的知識點總結

    Java是一門面向對象的語言。對象是Java程序中的基本實體。除了對象之外Java程序同樣處理基本數據。下面這篇文章主要給大家總結了關于Java中面向對象的知識點,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-02-02
  • 詳解java中保持compareTo和equals同步

    詳解java中保持compareTo和equals同步

    這篇文章主要介紹了詳解java中保持compareTo和equals同步的相關資料,需要的朋友可以參考下
    2017-03-03

最新評論

于田县| 台州市| 怀远县| 从化市| 富民县| 芜湖市| 分宜县| 永新县| 台江县| 佛坪县| 蓬莱市| 武乡县| 伊金霍洛旗| 榆中县| 措美县| 淅川县| 吴桥县| 荆州市| 寿阳县| 永兴县| 门头沟区| 五台县| 临桂县| 恭城| 包头市| 开远市| 温州市| 峨眉山市| 塘沽区| 抚松县| 长岭县| 巩义市| 始兴县| 小金县| 郴州市| 张家界市| 刚察县| 丹东市| 天津市| 琼中| 棋牌|