亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Spring @Transactional-隔離,傳播

Spring @Transactional-隔離,傳播

慕村9548890 2019-10-12 14:24:48
有人可以通過實際示例解釋注釋中的隔離和傳播參數@Transactional嗎?基本上,何時和為什么我應該選擇更改其默認值。
查看完整描述

3 回答

?
搖曳的薔薇

TA貢獻1793條經驗 獲得超6個贊

好的問題,盡管不是一個簡單的答案。


傳播


定義事務之間的關系。常用選項:


Required:代碼將始終在事務中運行。創建一個新事務或重用一個事務(如果有)。

Requires_new:代碼將始終在新事務中運行。如果存在當前事務,則將其掛起。

隔離


定義事務之間的數據契約。


Read Uncommitted:允許臟讀。

Read Committed:不允許臟讀。

Repeatable Read:如果在同一事務中兩次讀取一行,結果將始終相同。

Serializable:按順序執行所有事務。

在多線程應用程序中,不同的級別具有不同的性能特征。我認為,如果您了解dirty reads概念,便可以選擇一個不錯的選擇。


何時發生臟讀的示例:


  thread 1   thread 2      

      |         |

    write(x)    |

      |         |

      |        read(x)

      |         |

    rollback    |

      v         v 

           value (x) is now dirty (incorrect)

因此,可以設置一個合理的默認值(如果可以要求的話)Read Committed,它只能讓您讀取傳播級別為的其他正在運行的事務已提交的值Required。然后,如果您的應用程序有其他需求,則可以從那里開始。


一個實際的示例,該示例在進入provideService例程時始終在其中創建新事務,而在離開時總是在其中完成:


public class FooService {

    private Repository repo1;

    private Repository repo2;


    @Transactional(propagation=Propagation.REQUIRES_NEW)

    public void provideService() {

        repo1.retrieveFoo();

        repo2.retrieveFoo();

    }

}

如果我們改為使用Required,則在進入例程時如果事務已經打開,則事務將保持打開狀態。還要注意,a的結果rollback可能會有所不同,因為多次執行可能會參與同一事務。


我們可以通過測試輕松驗證行為,并查看結果隨傳播級別的不同:


@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:/fooService.xml")

public class FooServiceTests {


    private @Autowired TransactionManager transactionManager;

    private @Autowired FooService fooService;


    @Test

    public void testProvideService() {

        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

        fooService.provideService();

        transactionManager.rollback(status);

        // assert repository values are unchanged ... 

}

傳播水平為


Requires new:我們希望fooService.provideService()它不會回滾,因為它創建了它自己的子事務。


Required:我們希望一切都回滾而后備存儲保持不變。


查看完整回答
反對 回復 2019-10-12
?
莫回無

TA貢獻1865條經驗 獲得超7個贊

關于其他參數的足夠解釋由其他答案給出;但是,您要求提供一個真實的示例,以下示例闡明了不同傳播選項的目的:


假設您負責實施注冊服務,在該服務中向用戶發送確認電子郵件。您想到了兩個服務對象,一個用于注冊用戶,另一個用于發送電子郵件,后者在第一個中被稱為。例如這樣的事情:

/* Sign Up service */

@Service

@Transactional(Propagation=REQUIRED)

class SignUpService{

 ...

 void SignUp(User user){

    ...

    emailService.sendMail(User);

 }

}


/* E-Mail Service */

@Service

@Transactional(Propagation=REQUIRES_NEW)

class EmailService{

 ...

 void sendMail(User user){

  try{

     ... // Trying to send the e-mail

  }catch( Exception)

 }

}

您可能已經注意到第二個服務的傳播類型為REQUIRES_NEW,而且有可能引發異常(SMTP服務器關閉,電子郵件無效或其他原因)。您可能不希望整個過程回滾,例如從數據庫或其他事物中刪除用戶信息;因此,您在單獨的事務中調用第二個服務。


回到我們的示例,這一次您擔心數據庫的安全性,因此您可以通過以下方式定義DAO類:

/* User DAO */

@Transactional(Propagation=MANDATORY)

class UserDAO{

 // some CRUD methods

}

這就意味著無論何時創建DAO對象,從而可能創建對db的訪問,我們都需要確保從內部服務中進行調用,這意味著應該存在一個實時事務。否則將發生異常。因此,傳播的類型為MANDATORY。


查看完整回答
反對 回復 2019-10-12
  • 3 回答
  • 0 關注
  • 668 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號