自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入理解JTS平衡安全性和性能

開(kāi)發(fā) 后端
本文深入介紹了JTS平衡安全性和性能,希望對(duì)你有幫助,一起來(lái)看吧!

JTS 只是一個(gè)組件事務(wù)監(jiān)視器(有時(shí)也稱(chēng)為 對(duì)象事務(wù)監(jiān)視器(object transaction monitor)),或稱(chēng)為 CTM。大家可以看看這篇文章,Java理論和實(shí)踐: 理解JTS。

事務(wù)主要是一種異常處理機(jī)制。事務(wù)在程序中的用途與合法合同在日常業(yè)務(wù)中的用途相似:如果出了什么問(wèn)題它們可以幫助恢復(fù)。但由于大多數(shù)時(shí)間內(nèi)都沒(méi)實(shí)際 發(fā)生什么錯(cuò)誤,我們就希望能夠盡量減少它們的開(kāi)銷(xiāo)以及對(duì)其余時(shí)間的占用。我們?cè)趹?yīng)用程序中如何使用事務(wù)會(huì)對(duì)應(yīng)用程序的性能和可伸縮性產(chǎn)生很大的影響。

事務(wù)劃分

J2EE 容器提供了兩種機(jī)制用來(lái)定義事務(wù)的起點(diǎn)和終點(diǎn):bean 管理的事務(wù)和容器管理的事務(wù)。在 bean 管理的事務(wù)中,用 UserTransaction.begin() 和 UserTransaction.commit() 在 bean 方法中顯式開(kāi)始和結(jié)束一個(gè)事務(wù)。另一方面,容器管理的事務(wù)提供了更多的靈活性。通過(guò)在裝配描述符中為每個(gè) EJB 方法定義事務(wù)性屬性,您可以指定每個(gè)方法的事務(wù)性需求并讓容器確定何時(shí)開(kāi)始和結(jié)束一個(gè)事務(wù)。無(wú)論在哪種情況下,構(gòu)建事務(wù)的基本指導(dǎo)方針都是一樣的。

進(jìn)來(lái),出去

事務(wù)劃分的第一條規(guī)則是“盡量短小”。事務(wù)提供并發(fā)控制;這通常意味著資源管理器將代表您獲得您在事務(wù)期間訪問(wèn)的數(shù)據(jù)項(xiàng)的鎖,并且它必須一直持有這些鎖,直到事務(wù)結(jié)束。(請(qǐng)回憶一下本系列第 1 部分所討論的 ACID特性,其中“ACID”的“I”代表“隔離”(Isolation)。也就是說(shuō),一個(gè)事務(wù)的結(jié)果影響不到與該事務(wù)并發(fā)執(zhí)行的其它事務(wù)。)當(dāng)您擁有鎖時(shí),任何需要訪問(wèn)您鎖定的數(shù)據(jù)項(xiàng)的其它事務(wù)將不得不一直等待,直到您釋放鎖。如果您的事務(wù)很長(zhǎng),那些其它的所有事務(wù)都將被鎖定,您的應(yīng)用程序吞吐量將大幅度下降。

規(guī)則 1:使事務(wù)盡可能短小。

通過(guò)使事務(wù)盡量短小,您可以把阻礙其它事務(wù)的時(shí)間縮到最短,從而提高應(yīng)用程序的可伸縮性。保持事務(wù)盡可能短小的最好方法當(dāng)然是不在事務(wù)中間做任何不必要耗費(fèi)時(shí)間的事,特別是不要在事務(wù)中間等待用戶(hù)輸入。

開(kāi)始一個(gè)事務(wù),從數(shù)據(jù)庫(kù)檢索一些數(shù)據(jù),顯示數(shù)據(jù),然后在仍處于事務(wù)中時(shí)請(qǐng)用戶(hù)做出一個(gè)選擇可能比較誘人。千萬(wàn)別這么做!即使用戶(hù)注意力集中,也要花費(fèi)數(shù)秒來(lái)響應(yīng) ― 而在數(shù)據(jù)庫(kù)中擁有鎖數(shù)秒的時(shí)間已經(jīng)是很長(zhǎng)的了。如果用戶(hù)決定離開(kāi)計(jì)算機(jī),或許是去吃午餐或者甚至回家一天,會(huì)發(fā)生什么情況?應(yīng)用程序?qū)⒅缓脽o(wú)奈停機(jī)。在事務(wù)期間執(zhí)行 I/O 是導(dǎo)致災(zāi)難的秘訣。

規(guī)則 2:在事務(wù)期間不要等待用戶(hù)輸入。

將相關(guān)的操作歸在一起

由于每個(gè)事務(wù)都有不小的開(kāi)銷(xiāo),您可能認(rèn)為最好是在單個(gè)事務(wù)中執(zhí)行盡可能多的操作以使每個(gè)操作的開(kāi)銷(xiāo)達(dá)到最小。但規(guī)則 1 告訴我們長(zhǎng)事務(wù)對(duì)可伸縮性不利。那么如何實(shí)現(xiàn)最小化每個(gè)操作的開(kāi)銷(xiāo)和可伸縮性之間的平衡呢?

我們把規(guī)則 1 設(shè)置為邏輯上的極端 ― 每個(gè)事務(wù)一個(gè)操作 ― 這樣不僅會(huì)導(dǎo)致額外開(kāi)銷(xiāo),還會(huì)危及應(yīng)用程序狀態(tài)的一致性。假定事務(wù)性資源管理器維護(hù)應(yīng)用程序狀態(tài)的一致性(請(qǐng)回憶一下第 1 部分,其中“ACID”的“C”代表“一致性”(Consistency)),但它們依賴(lài)應(yīng)用程序來(lái)定義一致性的意思。實(shí)際上,我們?cè)诿枋鍪聞?wù)時(shí)使用的一致性的定義有點(diǎn)圓滑:應(yīng)用程序說(shuō)一致性是什么意思它就是什么意思。應(yīng)用程序把幾組應(yīng)用程序狀態(tài)的變化組織到幾個(gè)事務(wù)中,結(jié)果應(yīng)用程序的狀態(tài)就成了 定義上的(by definition)一致。然后資源管理器確保如果它必須從故障恢復(fù)的話,就把應(yīng)用程序狀態(tài)恢復(fù)到最近的一致?tīng)顟B(tài)。

在第 1 部分中,我們給出了一個(gè)在銀行應(yīng)用程序中將資金從一個(gè)帳戶(hù)轉(zhuǎn)移到另一個(gè)帳戶(hù)的示例。清單 1 展示了這個(gè)示例可能的 SQL 實(shí)現(xiàn),它包含 5 個(gè) SQL 操作(一個(gè)選擇,兩個(gè)更新和兩個(gè)插入操作):

清單 1. 資金轉(zhuǎn)移的樣本 SQL 代碼

  1.  
  2. SELECT accountBalance INTO aBalance   
  3. FROM Accounts WHERE accountId=aId;  
  4. IF (aBalance >= transferAmount) THEN   
  5. UPDATE Accounts   
  6. SET accountBalance = accountBalance - transferAmount  
  7. WHERE accountId = aId;  
  8. UPDATE Accounts   
  9. SET accountBalance = accountBalance + transferAmount  
  10. WHERE accountId = bId;  
  11. INSERT INTO AccountJournal (accountId, amount)  
  12. VALUES (aId, -transferAmount);  
  13. INSERT INTO AccountJournal (accountId, amount)  
  14. VALUES (bId, transferAmount);  
  15. ELSE 
  16. FAIL "Insufficient funds in account";  
  17. END IF 

如果我們把這個(gè)操作作為五個(gè)單獨(dú)的事務(wù)來(lái)執(zhí)行會(huì)發(fā)生什么情況?這樣不僅會(huì)使執(zhí)行速度變慢(由于事務(wù)開(kāi)銷(xiāo)),還會(huì)失去一致性。例如,如果一個(gè)人從帳戶(hù) A 取了錢(qián),作為執(zhí)行第一次 SELECT(檢查余額)和隨后的記入借方 UPDATE 之間的一個(gè)單獨(dú)事務(wù)的一部分,會(huì)發(fā)生什么情況?這樣會(huì)違反我們認(rèn)為這段代碼會(huì)強(qiáng)制遵守的業(yè)務(wù)規(guī)則 ― 帳戶(hù)余額應(yīng)該是非負(fù)的。如果在第一次 UPDATE 和第二次 UPDATE 之間系統(tǒng)失敗會(huì)發(fā)生什么情況?現(xiàn)在,當(dāng)系統(tǒng)恢復(fù)時(shí),錢(qián)已經(jīng)離開(kāi)了帳戶(hù) A 但還沒(méi)有記入帳戶(hù) B 的貸方,并且也無(wú)記錄說(shuō)明原因。這樣,哪個(gè)帳戶(hù)的所有者都不會(huì)開(kāi)心。

清單 1 中的五個(gè) SQL 操作是單個(gè)相關(guān)操作 ― 將資金從一個(gè)帳戶(hù)轉(zhuǎn)移到另一個(gè)帳戶(hù) ― 的一部分。因此,我們希望要么全部執(zhí)行它們,要么一個(gè)也不執(zhí)行,建議在單個(gè)事務(wù)中全部執(zhí)行它們。

規(guī)則 3:將相關(guān)操作歸到單個(gè)事務(wù)中。

理想化的平衡

規(guī)則 1 說(shuō)事務(wù)應(yīng)盡可能短小。清單 1 中的示例表明有時(shí)候我們必須把一些操作歸到一個(gè)事務(wù)中來(lái)維護(hù)一致性。當(dāng)然,它要依賴(lài)應(yīng)用程序來(lái)確定“相關(guān)操作”是由什么組成的。我們可以把規(guī)則 1 和 3 結(jié)合在一起,提供一個(gè)描述事務(wù)范圍的一般指導(dǎo),我們規(guī)定它為規(guī)則 4:

規(guī)則 4:把相關(guān)操作歸到單個(gè)事務(wù)中,但把不相關(guān)的操作放到單獨(dú)的事務(wù)中。

容器管理的事務(wù)

在使用容器管理的事務(wù)時(shí),不是顯式聲明事務(wù)的起點(diǎn)和終點(diǎn),而是為每個(gè) EJB 方法定義事務(wù)性需求。bean 的 assembly-descriptor 的 container-transaction 部分的 trans-attribute 元素中定義了事務(wù)模式。(清單 2 中顯示了一個(gè) assembly-descriptor 示例。)方法的事務(wù)模式以及狀態(tài) ― 調(diào)用方法是否早已在事務(wù)中被征用 ― 決定了當(dāng) EJB 方法被調(diào)用時(shí)容器應(yīng)該進(jìn)行下面幾個(gè)操作中的哪一個(gè):

征用現(xiàn)有事務(wù)中的方法。

創(chuàng)建一個(gè)新事務(wù),并征用該事務(wù)中的方法。

不征用任何事務(wù)中的方法。

拋出一個(gè)異常。

清單 2. 樣本 EJB 裝配描述符

  1. <assembly-descriptor>  
  2. ...  
  3. <container-transaction>  
  4. <method>  
  5. <ejb-name>MyBean</ejb-name>  
  6. <method-name>*</method-name>  
  7. </method>  
  8. <trans-attribute>Required</trans-attribute>  
  9. </container-transaction>  
  10. <container-transaction>  
  11. <method>  
  12. <ejb-name>MyBean</ejb-name>  
  13. <method-name>logError</method-name>  
  14. </method>  
  15. <trans-attribute>RequiresNew</trans-attribute>  
  16. </container-transaction>  
  17. ...  
  18. </assembly-descriptor> 

那么我們應(yīng)該為自己的 bean 方法選擇哪種模式呢?對(duì)于會(huì)話 bean 和消息驅(qū)動(dòng) bean,您通常想使用 Required 來(lái)確保每個(gè)調(diào)用都被作為事務(wù)的一部分執(zhí)行,但仍將允許方法作為一個(gè)更大的事務(wù)的組件。請(qǐng)小心使用 RequiresNew ;只有在確定自己的方法的行為應(yīng)該與調(diào)用您的方法的行為分開(kāi)提交時(shí),才應(yīng)該使用這種模式。 RequiresNew 一般情況下只和與系統(tǒng)中其它對(duì)象關(guān)系很少或沒(méi)什么關(guān)系的對(duì)象(比如日志對(duì)象)一起使用。(把 RequiresNew 與日志對(duì)象一起使用比較有意義,因?yàn)槟赡芟M诓还芡鈬聞?wù)是否提交的情況下提交日志消息。)

RequiresNew 使用不當(dāng)會(huì)導(dǎo)致與上面的描述相似的情況,其中,清單 1 中的代碼在五個(gè)分開(kāi)的事務(wù)而不是一個(gè)事務(wù)中執(zhí)行,這樣會(huì)使應(yīng)用程序處于不一致?tīng)顟B(tài)。

對(duì)于 CMP(容器管理的持久性,container-managed persistence)實(shí)體 bean,通常是希望使用 Required 。 Mandatory 也是一個(gè)合理的選項(xiàng),特別是在最初開(kāi)發(fā)時(shí);這將會(huì)警告您實(shí)體 bean 方法在事務(wù)外被調(diào)用這種情況,這時(shí)可能會(huì)指出一個(gè)部署錯(cuò)誤。您幾乎從不希望把 RequiresNew 和 CMP 實(shí)體 bean 一起使用。 NotSupported 和 Never 旨在用于非事務(wù)性資源,比如 Java 事務(wù) API(Java Transaction API,JTA)事務(wù)中無(wú)法征用的外部非事務(wù)性系統(tǒng)或事務(wù)性系統(tǒng)的適配器。

如果 EJB 應(yīng)用程序設(shè)計(jì)得當(dāng),應(yīng)用上面的事務(wù)模式指導(dǎo)往往會(huì)自然地產(chǎn)生規(guī)則 4 建議的事務(wù)劃分。原因是 J2EE 體系架構(gòu)鼓勵(lì)把應(yīng)用程序分解為最小的方便處理的塊,并且每個(gè)塊都作為一個(gè)單獨(dú)的請(qǐng)求被處理( 不管是以 HTTP 請(qǐng)求的形式還是作為在 JMS 隊(duì)列中排隊(duì)的消息的結(jié)果)。

重溫隔離

在第 1 部分中,我們定義了 隔離(isolation)的意思是:一個(gè)事務(wù)的影響對(duì)與該事務(wù)并發(fā)執(zhí)行的其它事務(wù)是不可見(jiàn)的;從事務(wù)的角度來(lái)看,好象事務(wù)是連續(xù)執(zhí)行而非并行執(zhí)行。盡管事務(wù)性資源管理器經(jīng)??梢酝瑫r(shí)處理許多事務(wù)并提供隔離的假象,但有時(shí)隔離限制實(shí)際上要求把新事務(wù)延遲到現(xiàn)有事務(wù)完成后才開(kāi)始。由于完成一個(gè)事務(wù)至少包括一個(gè)同步磁盤(pán) I/O(寫(xiě)到事務(wù)日志),這就會(huì)把每秒的事務(wù)數(shù)限制到接近每秒的寫(xiě)磁盤(pán)次數(shù),這對(duì)可伸縮性不利。

實(shí)際上,通常是充分放松隔離需求以允許更多的事務(wù)并發(fā)執(zhí)行并使系統(tǒng)響應(yīng)能夠得到改善,使可伸縮性變得更強(qiáng)。幾乎所有的數(shù)據(jù)庫(kù)都支持標(biāo)準(zhǔn)隔離級(jí)別:讀未提交的(Read Uncommitted)、讀已提交的(Read Committed)、可重復(fù)的讀(Repeatable Read) 和可串行化的(Serializable)。

不幸的是,為容器管理的事務(wù)管理隔離目前是在 J2EE 規(guī)范的范圍之外。但是,許多 J2EE 容器,比如 IBM WebSphere 和 BEA WebLogic,將提供特定于容器的擴(kuò)展,這些擴(kuò)展允許您以每方法(per-method)為基礎(chǔ)設(shè)置事務(wù)隔離級(jí)別,設(shè)置方法與在裝配描述符中設(shè)置事務(wù)模式的方法相同。對(duì)于 bean 管理的事務(wù),您可以通過(guò) JDBC 或者其它資源管理器連接設(shè)置隔離級(jí)別。

為闡明隔離級(jí)別之間的差異,我們首先把幾個(gè)并發(fā)危險(xiǎn)分類(lèi) ― 這幾種危險(xiǎn)是當(dāng)沒(méi)有適當(dāng)?shù)馗綦x時(shí)一個(gè)事務(wù)可能會(huì)干涉另一個(gè)事務(wù)的情況。下列的所有這些危險(xiǎn)都與這種情況( 第二個(gè)事務(wù)已經(jīng)啟動(dòng)后第一個(gè)事務(wù)變得對(duì)第二個(gè)事務(wù) 可見(jiàn))的結(jié)果有關(guān):

臟讀(Dirty Read):當(dāng)一個(gè)事務(wù)的中間(未提交的)結(jié)果對(duì)另一個(gè)事務(wù)可見(jiàn)時(shí)就會(huì)發(fā)生這種情況。

不可重復(fù)的讀(Unrepeatable Read):當(dāng)一個(gè)事務(wù)讀取一個(gè)數(shù)據(jù)項(xiàng),然后重新讀取這個(gè)數(shù)據(jù)項(xiàng)并看到不同的值時(shí)就是發(fā)生了這種情況。

虛讀(Phantom Read):當(dāng)一個(gè)事務(wù)執(zhí)行返回多個(gè)行的查詢(xún),稍后再次執(zhí)行同一個(gè)查詢(xún)并看到第一次執(zhí)行該查詢(xún)沒(méi)出現(xiàn)的額外行時(shí)就是發(fā)生了這種情況。

四個(gè)標(biāo)準(zhǔn)隔離級(jí)別與這三個(gè)隔離危險(xiǎn)相關(guān),如表 2 所示。最低的隔離級(jí)別“讀未提交的”并不能保護(hù)事務(wù)不被其它事務(wù)更改,但它的速度最快,因?yàn)樗恍枰獱?zhēng)奪讀鎖。最高的隔離級(jí)別“可串行化的”與上面給出的隔離的定義相當(dāng);每個(gè)事務(wù)好象都與其它事務(wù)的影響完全隔離。

表 2. 事務(wù)隔離級(jí)別

事務(wù)隔離級(jí)別

對(duì)于大多數(shù)數(shù)據(jù)庫(kù),缺省的隔離級(jí)別為“讀已提交的”,這是個(gè)很好的缺省選擇,因?yàn)樗柚故聞?wù)在事務(wù)中的任何給定的點(diǎn)看到應(yīng)用程序數(shù)據(jù)的不一致視圖。“讀已提交的”是一個(gè)很不錯(cuò)的隔離級(jí)別,用于大多數(shù)典型的短事務(wù),比如獲取報(bào)表數(shù)據(jù)或獲取要顯示給用戶(hù)的數(shù)據(jù)的時(shí)候(多半是作為 Web 請(qǐng)求的結(jié)果),也用于將新數(shù)據(jù)插入到數(shù)據(jù)庫(kù)的情況。

當(dāng)您需要所有事務(wù)間有較高級(jí)別的一致性時(shí),使用較高的隔離級(jí)別“可重復(fù)的讀”和“可串行化的”比較合適,比如在清單 1 示例中,您希望從檢查余額以確保有足夠的資金到您實(shí)際取錢(qián)期間賬戶(hù)余額一直保持不變;這就要求至少要用“可重復(fù)的讀”隔離級(jí)別。在數(shù)據(jù)一致性絕對(duì)重要的情況下,比如審核記帳數(shù)據(jù)庫(kù)以確保一個(gè)帳戶(hù)的所有借方金額和貸方金額的總數(shù)等于它目前的余額時(shí),可能還需要防止創(chuàng)建新行。這種情況下就需要使用“可串行化的”隔離級(jí)別。

最低的隔離級(jí)別“讀未提交的”很少使用。它適用于您只需要獲得近似值,否則查詢(xún)將導(dǎo)致您不希望的性能開(kāi)銷(xiāo)這種情況。當(dāng)您想要估計(jì)一個(gè)變化很快的數(shù)量,如定單數(shù)或者今天所下定單的總金額(以美元為單位)時(shí)一般使用““讀未提交的”。

因?yàn)楦綦x和可伸縮性之間實(shí)際是一種此消彼長(zhǎng)的關(guān)系,所以您在為事務(wù)選擇隔離級(jí)別時(shí)應(yīng)該小心行事。選擇太低的級(jí)別對(duì)數(shù)據(jù)比較危險(xiǎn)。選擇太高的級(jí)別可能對(duì)性能不利,盡管負(fù)載比較輕時(shí)可能不會(huì)這樣。一般來(lái)說(shuō),數(shù)據(jù)一致性問(wèn)題比性能問(wèn)題更嚴(yán)重。如果拿不準(zhǔn),應(yīng)該以小心為主,選擇一個(gè)較高的隔離級(jí)別。這就引出了規(guī)則 5:

規(guī)則 5:使用保證數(shù)據(jù)安全 style="COLOR: #000000" href="http://safe.it168.com/" target=_blank>安全的最低隔離級(jí)別,但如果拿不準(zhǔn),請(qǐng)使用“可串行化的”。

即使您打算剛開(kāi)始時(shí)以小心為主并希望結(jié)果性能可以接受 ―(被稱(chēng)為“拒絕和祈禱(denial and prayer)”的性能管理技術(shù) ― 很可能是最常用的性能策略,盡管大多數(shù)開(kāi)發(fā)者都不承認(rèn)這一點(diǎn)),在開(kāi)發(fā)組件時(shí)考慮隔離需求也是有利的。您應(yīng)該努力編寫(xiě)能夠容忍級(jí)別較低但實(shí)用的隔離級(jí)別的事務(wù),這樣,當(dāng)稍后性能成為問(wèn)題時(shí),自己就不會(huì)陷入困境。因?yàn)槟枰婪椒ㄕ谧鍪裁匆约斑@個(gè)方法中隱藏了什么一致性假設(shè)來(lái)正確設(shè)置隔離級(jí)別,那么在開(kāi)發(fā)期間仔細(xì)說(shuō)明并發(fā)需求和假設(shè),以便在裝配應(yīng)用程序時(shí)幫助作出正確的決定也不失為一個(gè)好主意。

結(jié)束語(yǔ)

本文中提供的許多指導(dǎo)可能看起來(lái)有點(diǎn)互相矛盾,因?yàn)橄笫聞?wù)劃分和隔離這種問(wèn)題本來(lái)就是此消彼長(zhǎng)的。我們正在努力平衡安全性(如果我們不關(guān)心安全性,那就壓根不必用事務(wù)了)和我們用來(lái)提供安全限度的工具的性能開(kāi)銷(xiāo)。正確的平衡要依賴(lài)許多因素,包括與系統(tǒng)故障或當(dāng)機(jī)時(shí)間相關(guān)的代價(jià)或損害以及組織的風(fēng)險(xiǎn)承受能力。

【編輯推薦】

  1. java/.net語(yǔ)言及IDE簡(jiǎn)易對(duì)比
  2. java中的類(lèi)和方法的修飾符
  3. 關(guān)于Java對(duì)象序列化您不知道的5件事
  4. Java為什么如此深受廣大開(kāi)發(fā)者的青睞?
  5. Javascript中的函數(shù)聲明和函數(shù)表達(dá)式
責(zé)任編輯:于鐵 來(lái)源: 互聯(lián)網(wǎng)
相關(guān)推薦

2023-06-01 15:17:17

2019-04-08 16:50:33

前端性能監(jiān)控

2023-06-29 00:17:58

DevSecOps軟件開(kāi)發(fā)

2009-06-19 14:10:42

Java多態(tài)性

2024-11-14 16:02:43

2009-11-09 17:40:33

WCF配置可靠性

2024-06-06 09:58:13

2009-10-12 10:52:47

RHEL5安全性

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數(shù)據(jù)結(jié)構(gòu)hash函數(shù)

2020-07-21 08:26:08

SpringSecurity過(guò)濾器

2015-05-11 10:42:17

混合云性能混合云安全SLA

2012-11-08 14:47:52

Hadoop集群

2012-08-31 10:00:12

Hadoop云計(jì)算群集網(wǎng)絡(luò)

2013-07-31 10:04:42

hadoopHadoop集群集群和網(wǎng)絡(luò)

2025-01-13 13:00:00

Go網(wǎng)絡(luò)框架nbio

2022-01-18 10:48:12

HTTPS加密安全漏洞

2009-06-25 13:21:00

JTS

2013-01-09 10:04:55

2017-03-28 21:39:41

ErrorsStack trace代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)