3 回答

TA貢獻(xiàn)1831條經(jīng)驗(yàn) 獲得超9個(gè)贊
好的問(wèn)題,盡管不是一個(gè)簡(jiǎn)單的答案。
傳播
定義事務(wù)之間的關(guān)系。常用選項(xiàng):
Required:代碼將始終在事務(wù)中運(yùn)行。創(chuàng)建一個(gè)新事務(wù)或重用一個(gè)事務(wù)(如果有)。
Requires_new:代碼將始終在新事務(wù)中運(yùn)行。如果存在當(dāng)前事務(wù),則將其掛起。
隔離
定義事務(wù)之間的數(shù)據(jù)契約。
Read Uncommitted:允許臟讀。
Read Committed:不允許臟讀。
Repeatable Read:如果在同一事務(wù)中兩次讀取一行,結(jié)果將始終相同。
Serializable:按順序執(zhí)行所有事務(wù)。
在多線程應(yīng)用程序中,不同的級(jí)別具有不同的性能特征。我認(rèn)為,如果您了解dirty reads概念,便可以選擇一個(gè)不錯(cuò)的選擇。
何時(shí)發(fā)生臟讀的示例:
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
因此,可以設(shè)置一個(gè)合理的默認(rèn)值(如果可以要求的話)Read Committed,它只能讓您讀取傳播級(jí)別為的其他正在運(yùn)行的事務(wù)已提交的值Required。然后,如果您的應(yīng)用程序有其他需求,則可以從那里開始。
一個(gè)實(shí)際的示例,該示例在進(jìn)入provideService例程時(shí)始終在其中創(chuàng)建新事務(wù),而在離開時(shí)總是在其中完成:
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
如果我們改為使用Required,則在進(jìn)入例程時(shí)如果事務(wù)已經(jīng)打開,則事務(wù)將保持打開狀態(tài)。還要注意,a的結(jié)果rollback可能會(huì)有所不同,因?yàn)槎啻螆?zhí)行可能會(huì)參與同一事務(wù)。
我們可以通過(guò)測(cè)試輕松驗(yàn)證行為,并查看結(jié)果隨傳播級(jí)別的不同:
@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()它不會(huì)回滾,因?yàn)樗鼊?chuàng)建了它自己的子事務(wù)。
Required:我們希望一切都回滾而后備存儲(chǔ)保持不變。

TA貢獻(xiàn)2037條經(jīng)驗(yàn) 獲得超6個(gè)贊
關(guān)于其他參數(shù)的足夠解釋由其他答案給出;但是,您要求提供一個(gè)真實(shí)的示例,以下示例闡明了不同傳播選項(xiàng)的目的:
假設(shè)您負(fù)責(zé)實(shí)施注冊(cè)服務(wù),在該服務(wù)中向用戶發(fā)送確認(rèn)電子郵件。您想到了兩個(gè)服務(wù)對(duì)象,一個(gè)用于注冊(cè)用戶,另一個(gè)用于發(fā)送電子郵件,后者在第一個(gè)中被稱為。例如這樣的事情:
/* 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)
}
}
您可能已經(jīng)注意到第二個(gè)服務(wù)的傳播類型為REQUIRES_NEW,而且有可能引發(fā)異常(SMTP服務(wù)器關(guān)閉,電子郵件無(wú)效或其他原因)。您可能不希望整個(gè)過(guò)程回滾,例如從數(shù)據(jù)庫(kù)或其他事物中刪除用戶信息;因此,您在單獨(dú)的事務(wù)中調(diào)用第二個(gè)服務(wù)。
回到我們的示例,這一次您擔(dān)心數(shù)據(jù)庫(kù)的安全性,因此您可以通過(guò)以下方式定義DAO類:
/* User DAO */
@Transactional(Propagation=MANDATORY)
class UserDAO{
// some CRUD methods
}
這就意味著無(wú)論何時(shí)創(chuàng)建DAO對(duì)象,從而可能創(chuàng)建對(duì)db的訪問(wèn),我們都需要確保從內(nèi)部服務(wù)中進(jìn)行調(diào)用,這意味著應(yīng)該存在一個(gè)實(shí)時(shí)事務(wù)。否則將發(fā)生異常。因此,傳播的類型為MANDATORY。
添加回答
舉報(bào)