【Sqlserver系列】【轉載】事物與鎖

1   概述數據庫

本篇文章簡要對事物與鎖的分析比較詳細,所以就轉載了。安全

2   具體內容併發

併發能夠定義爲多個進程同時訪問或修改共享數據的能力。處於活動狀態而互不干涉的併發用戶進程的數量越多,數據庫系統的併發性就越好。當一個正在修改數據的進程阻止了其餘進程讀取該數據,或者當一個正在讀取數據的進程阻止了其餘進程修改該數據,併發性就下降了。本文用術語「讀取」或者「訪問」描述數據上的SELECT操做,用「寫入」或「修改」描述數據上的INSERT,UPDATE以及DELETE操做。高併發

通常地,數據庫系統能夠採用兩種方式來管理併發數據訪問,樂觀併發控制和悲觀併發控制。性能

併發控制模型

對於任何一種併發控制模式,若是兩個事務試圖同一時刻修改數據的話都會產生衝突。這兩種模式之間的區別在於,是在衝突發生前進行防止,仍是發生後採起某種方法來處理衝突。學習

悲觀併發控制

對於悲觀併發控制,該模型假定系統中存在足夠多的數據修改操做,以至於事務的任何數據讀取/修改操做均可能受到其餘事務數據修改操做的影響,即假定衝突老是會發生的。SQL Server默認經過 (lock)來保證讀者和寫者之間的互斥。

樂觀併發控制

對於樂觀併發控制,該模型假定系統中存在很是少的相互衝突的數據修改操做,以至任何單獨的事務都不太可能修改其它事務正在修改的數據。樂觀併發控制默認採用版本控制來處理併發。spa

例如,在讀取數據時咱們會獲得一個數據的版本version 1,當須要修改數據時,咱們先檢查數據的版本是否是version 1,若是是就修改數據;若是不是,就說明在當前事務的讀操做和寫操做之間已經有別的事務對數據進行了修改(每次修改操做都會使得數據的版本+1),SQL Server將會產生一個錯誤消息,由上層應用程序響應此錯誤。設計

事務處理

不管是採用哪一種併發控制模型,對於事務的理解是相當重要的。事務是SQL Server中任務的基本單位。典型地,它由幾個讀取和修改數據的SQL命令組成,可是直到COMMIT命令被執行之後,修改操做才被認爲是終結了。

ACID屬性

原子性(Atomicity)
SQL Server保證事務的原子性。原子性指的是每一個事務要麼所有執行,要麼什麼都不執行。也就是說,若是一個事務提交了,它形成的全部效果都會被保留。若是停止了,其全部效果都會被撤銷。3d

一致性(Consistency)
一致性屬性確保事務不容許系統到達一個不許確的邏輯狀態——數據必須老是保持邏輯上的正確。即便在發生系統故障時,約束和規則必須獲得保證。(一致性通常被原子性、隔離性以及持久性所涵蓋,而且概念上會產生重複)版本控制

隔離性(Isolation)
隔離性會將併發事務與其餘併發事務的更新操做分隔開。當該事務正在執行時,其餘事務是沒法看到進行中的任務的。SQL Server會在事務之間自動實現隔離。它採用鎖定數據或者行版本使得多個併發事務可以併發操做數據,以防止致使不正確結果。

隔離性意味着事務必須在不干擾其餘事務的前提下獨立執行。換言之,在事務執行完畢以前,其所訪問的數據不能受系統其餘部分的影響。

持久性(Durability)
當事務提交以後,SQL Server的持久性屬性就會確保該事務的做用持續存在(即便發生系統故障)。若是在事務進行過程當中發生系統故障,事務就會被徹底撤銷,不會在數據上遺留部分做用。若是在事務的提交確認被髮送到調用的程序以後馬上發生故障,數據庫會確保該事務的存在。預寫式日誌以及SQL Server啓動恢復階段的事務自動回滾/自動重作機制可以確保持久性。

一致性問題

事務老是所有支持ACID屬性的。事務可能還會表現出一些另外的行爲,稱爲「一致性問題」,而我並不認爲它們是「問題」。它們僅僅是可能存在的行爲,而用戶可以決定容許哪些和阻止哪些,用戶對於隔離級別的選擇決定了下列這些行爲中哪些是被容許的。

丟失更新

當兩個事務讀取相同數據而且都處理該數據(修改了它的值),而後都嘗試更新原來的數據成新的值時,這種行爲就會發生了。第二個事務可能徹底覆蓋掉第一個所完成的更新。
時間 取款事務A 取款事務B
T1 開始事務  
T2   開始事務
T3   查詢帳戶餘額爲1000
T4 查詢帳戶餘額爲1000  
T5   取出100,存款餘額爲900
T6 取出300,存款餘額爲700  
T7 提交事務  
T8   提交事務

最終帳戶餘額爲900,取款事務A的更新丟失了。丟失更新是這些行爲中惟一一個用戶可能在全部狀況下都想避免的行爲。

髒讀

這種行爲在一個事務讀取未提交數據時會發生,若是一個事務修改了數據可是還沒有提交修改,而另外一個正在讀取數據的事務會讀到這個修改從而致使一種不一致的狀態發生。
時間 查詢事務A 取款事務B
T1 開始事務  
T2   開始事務
T3   查詢帳戶餘額爲1000
T4   取出100,存款餘額爲900
T5 查詢帳戶餘額爲900  
T6   撤銷事務,恢復爲1000
T7 提交事務  

查詢事務A讀取到取款事務B還未提交的餘額900。
默認狀況下,髒讀是不容許的。謹記:更新數據的事務是沒法控制別的事務在它提交以前讀取其數據的,這是由讀取數據的事務來決定是否想要讀取未必會被提交的數據。

不可重複讀

這種行爲又被稱爲「不一致分析」。若是同一事務分別以兩個讀操做讀取相同資源時,可能會獲得不一樣的值,這就是不可重複讀。
時間 查詢事務A 取款事務B
T1 開始事務  
T2   開始事務
T3 查詢帳戶餘額爲1000  
T4   取出100,存款餘額爲900
T5 查詢帳戶餘額爲900  
T6   提交事務
T7 提交事務  

查詢事務A兩次讀取餘額獲取到不一樣結果。

幻讀

這種行爲產生於一個數據集內的部分數據被修改時。若是事務A讀取與搜索條件相匹配的若干行。事務B以插入或刪除行等方式來修改事務A的結果集,而後再提交。
時間 取款記錄處理事務A 取款事務B
T1 開始事務  
T2   開始事務
T3 查詢到5條取款記錄  
T4   查詢餘額爲1000元
T5   取出100,存款餘額爲900
T6 查詢到6條取款記錄  
T7 提交事務  
T8   提交事務

對於取款記錄處理事務A,兩次查詢的結果集不一樣。

 
事務的行爲取決於隔離級別,也就是決定上述四種行爲中那些是被容許的。併發控制模型決定了隔離級別是如何實現的——或者更明確的講,決定了SQL Sever是如何確保用戶所不想要的行爲不發生的。

隔離級別

SQL Server支持五種隔離級別來控制讀操做的行爲。其中三個只在悲觀併發模型中可用,一個只在樂觀併發模型中可用。剩下的一個在兩個模式下都是可用的。

未提交讀

除了丟失更新之外,上面提到的其餘行爲均可能發生。未提交讀是經過使讀操做不佔用任何鎖來實現的,當前事務可以讀取其餘事務已經修改過可是還沒有提交的數據。

當採用未提交讀時,用戶是放棄了對高一致性數據的把握而趨向於支持系統的高併發能力,使用戶不會再互相鎖定對方。那麼,什麼時候才應該選擇未提交讀呢?顯然,每筆數據都須保證平衡的金融交易是不適合的。而對於某些決策支持分析來講可能會很適合(譬如,須要察看銷售走勢時),由於徹底沒有必要作到徹底精確並且會帶來併發性能的提高,所以是至關值得的。

已提交讀

已提交讀是數據庫引擎的默認級別。SQL Server 2005支持兩種已提交讀的隔離級別,這種隔離級別既能夠是樂觀的也能夠是悲觀的,默認採用悲觀併發控制。爲了區分,悲觀實現稱「已提交讀(鎖定)」,樂觀實現稱爲」已提交讀(快照)」。

已提交讀隔離級別保證了一個操做不會讀到別的程序已經修改可是還沒有提交的數據。若是別的事務正在更新數據並所以在數據行上持有排它鎖,當前的事務就必須等待這些鎖釋放後才能使用這個數據(不管是讀取仍是修改)。一樣地,事務必須至少在要被訪問的數據上加上共享鎖,其餘事務能夠讀取數據可是不能修改數據。默認,共享鎖在數據讀取事後就被釋放掉,而無需在事務的持續時間內保留。

已提交讀(快照),也能保證一個操做不會讀到未提交數據,但不是經過迫使其餘進程等待的方式。對於已提交讀(快照),每當一行數據被修改後,SQL Server就會生成該行數據前一次已提交值的一個版本(version),被修改的數據仍舊被鎖定着,可是其餘進程能夠看到該數據在更新操做開始以前的版本。

可重複讀

可重複讀是一種悲觀的隔離級別。它在已提交讀的基礎上增長了新的屬性:確保當事務從新訪問數據或查詢被再一次執行時,數據將再也不發生改變。換句話說,在一個事務中執行相同的查詢兩次是不會看到由其餘事務所形成的任何數據的改變的。然而,可重複讀隔離級別仍是容許幻讀的出現。

在某些狀況下,防止不可重複讀是用戶嚮往的一種安全措施。可是世上沒有免費的午飯,這種額外的措施所帶來的開銷是事務中全部的共享鎖必須保留到事務完成爲止。

排它鎖必須老是保留到事務結束爲止,不管採用何種隔離級別或者併發模型,這樣事務才能在須要時被回滾。若是鎖提早釋放了,就不太可能完成撤銷操做,由於其餘併發事務可能已經使用了同一數據,而且修改了它的值。
只要事務是打開的,沒有其餘用戶能夠修改被該事務所訪問的數據。顯然這會嚴重下降併發性和性能。所以,若是事務不保持簡短或者編寫應用程序時沒有可以注意到這樣潛在的鎖競爭問題,將會致使大量的事務由於等待鎖釋放而掛起。

快照

快照隔離是一種樂觀隔離級別,相似於已提交讀(快照),若是當前版本被鎖定住時,它容許其餘事務讀取已提交數據的早期版本。快照隔離和已提交讀(快照)的區別與(早期版本該有多早、保留多少個早期版本)這個問題相關,咱們在行版本控制小節中詳述。儘管快照隔離所避免的行爲和可串行化所避免的是相同的,可是快照隔離並非真正意義上的可串行化隔離級別。對於快照隔離,可能會有兩個個事務同時執行,並引發一個任何序列化執行都不可能產生的結果。

 

若是兩個事務並行地運行,最終會交換titles表裏兩本書的價格。然而,不存在一種序列化執行的方式最終致使數值的交換。不管是先執行事務1而後執行事務2,仍是先執行事務2再執行事務1,任何序列順序最終將致使兩本書擁有相同的價格。

可串行化

可串行化也是一種悲觀隔離級別。可串行化隔離級別在可重複讀的基礎上增長了新的屬性:確保在從新執行查詢時,SQL Server不會在中間的過渡期增長新的行。換句話說,若是同一事物在相同的查詢被執行兩次的話,幻讀不會出現。可串行化也所以成爲最健壯的悲觀隔離級別,由於防止了以前所描述的全部可能的「不一致問題「。

額外的安全措施一定會帶來額外的開銷。可串行化隔離級別下,事務中的全部共享鎖都必須保留到事務完成爲止。另外,執行可串行化隔離級別不只須要鎖定已讀數據,還須要鎖定那些不存在的數據,參看後面的鍵範圍鎖。

鎖定

對於多用戶數據庫系統而言,鎖定是一個相當重要的功能。鎖在悲觀和樂觀併發控制模型中都有所應用,儘管在每種模型中其餘事務處理「被鎖定數據」的方式是不一樣的。在悲觀模型中,寫者老是阻塞讀者和寫者,而讀者也會阻塞寫者。對於樂觀模型,惟一可能發生的阻塞是寫者阻塞其餘寫者。

鎖定的基本概念

SQL Server可使用幾種不一樣方式來鎖定數據,舉例來講,讀操做獲取共享鎖而寫操做獲取排他鎖。更新鎖在更新操做的開頭部分獲取。SQL Server會自動獲取並釋放全部這些類型的鎖。它還負責管理鎖定模式之間的兼容性,解決死鎖問題,並在須要的時候進行鎖升級。它在表、表的分頁、索引鍵以及單獨的數據行上支配鎖。

鎖定類型

共享鎖

當數據被讀取時,SQL Server自動獲取共享鎖。許多事務能夠在同一數據上都持有共享鎖,可是沒有事務能夠在已經有一個共享鎖存在的狀況下,在該數據上再獲取一個排他鎖。通常的,當數據已經讀取完畢後,共享受就會當即釋放掉,可是能夠經過使用查詢提示或者採用不一樣的事務隔離級別來改變這種默認方式。

排它鎖

當數據被插入、更新或者刪除操做修改之後,SQL Server就會自動獲取數據上的排他鎖。一次只能有一個事務持有特定數據資源上的排它鎖。排它鎖會保留到事務結束爲止。這就意味着被修改的數據一般在當前事務提交或者回滾以前對其餘事務來講是不可用的。其餘事務能夠經過使用查詢提示來讀取被排它鎖鎖定的數據。

更新鎖

更新鎖實際上並非一種獨立的鎖,他是共享鎖和排他鎖的一種混合。當SQL Server執行一個數據修改操做可是首先須要搜索表以尋找到被修改的資源時,更新鎖就會被獲取。更新鎖可以預防鎖升級而產生的死鎖,SQL Server保證更新鎖的持有者可以將其轉化成排他鎖,死鎖就能夠避免了。
 

更新鎖自己不足以使用戶可以修改數據——全部的數據修改都要求被修改的數據資源上存在一個排它鎖。只要有一個事務對資源持有更新鎖,其它事務就沒法獲取該資源的更新鎖或者排他鎖了。持有更新鎖的事務可以將其轉換成該資源上的排它鎖,由於更新鎖避免了與其餘進程之間的鎖的不兼容。能夠將更新鎖看做是「意圖更新鎖」,這纔是它實際所扮演的角色。更新鎖會保留到事務結束或者當它轉換成排他鎖。

不要被鎖的名字誤導,更新鎖並不僅是針對更新操做而設計的。SQL Server使用更新鎖適用於任何須要進行實際修改以前搜索數據的數據修改操做。這樣的操做包括受限更新及刪除,也包括在帶有彙集索引的表上進行的插入操做。對於後面一種狀況,SQL Server必須先搜索數據(使用匯集索引)以找到正確的位置來插入新的記錄。當SQL Server只進行到搜索階段時,它會採用更新鎖來保護數據,而只有當它找到正確的位置並開始插入之後纔將更新鎖升級爲排他鎖。

意向鎖

意向鎖實際上並非一種獨立的鎖定模式。你能夠擁有意向共享鎖,意向排他鎖甚至意向更新鎖。因爲SQL Server能夠在不一樣級別的粒度上獲取鎖,所以須要一種機制來指出一個資源上的組件已經被鎖定了。例如,若是一個事務試圖鎖定一張表,SQL Server須要採用一種機制來判斷是否這張表上的行(或者一個分頁)已經被鎖住了。意向鎖就是起這個做用,在瞭解鎖的粒度時會深刻研究意向鎖。

鍵範圍鎖

只在 可串行化隔離級別中爲了鎖定必定範圍內的數據而被獲取。共享鎖和排它鎖能夠在表、分頁、行或者鍵上獲取,而鍵鎖只能從鍵上獲取。

鎖的粒度

SQL Server能夠鎖定表、分頁、行等級別的數據資源。它一樣能夠鎖定索引鍵及必定範圍內的索引鍵。謹記若是表上存在彙集索引,數據行就在彙集索引的葉級,而且是由鍵鎖而不是行鎖來鎖定它們的。
 
SQL Server對每一個鎖都進行追蹤而且包含了鎖、被鎖定資源(行、鍵或分頁)、鎖的模式以及特定資源的一個標識符。當一個事務申請鎖時,SQL Server會將所申請的鎖與已經申請的鎖進行比較並尋找徹底匹配資源類型以及標識符的鎖。可是,若是一個事務在表中的某行上佔有一個排他鎖,別的事務可能會嘗試在整張表上獲取一個鎖。
 
因爲是兩種不一樣的資源,SQL Server不會找到一個徹底的匹配,這就須要使用意向鎖了。SQL Server會記錄在表的一行記錄上擁有排他鎖的事務也在包含該行記錄的分頁上佔有一個意向鎖,以及在包含該行記錄的這張表上擁有一個意向鎖。當其餘事務試圖獲取這張表上的一個排他鎖時,其餘事務將會被阻塞。

鍵鎖

SQL Server支持兩種類型的鍵鎖,而它採用哪一種類型則取決於當前事務的隔離級別。若是隔離級別是已經提交讀、可重複讀或者快照,SQL Server會在處理查詢時嘗試鎖定實際被訪問的索引鍵。對於彙集索引的表而言,數據行就是索引的葉級別,而用戶能夠看到所獲取的鍵鎖。若是表是堆結構的話,用戶可能會看到非彙集索引上的鍵鎖以及實際數據上的行鎖。

若是隔離級別是可串行化,狀況就有所不一樣了。爲了防止幻讀,若是一個事務中掃描了一個範圍內的數據就須要充分鎖定住該表以確保沒人可以插入新值到已掃描的範圍內。在SQL Server早期版本中是經過鎖定整個分頁甚至整張表來保證這一點的。在許多狀況下,這可能致使了更大範圍的數據被鎖定住了,形成了沒必要要的資源競爭。SQL Server 2005採用了一種稱爲「鍵範圍鎖」的單獨鎖模式,與索引中的特定鍵值相關聯並代表在索引中這兩個鍵之間的全部值被鎖定住了。

鎖的兼容性

鎖簡稱

簡單兼容性矩陣

完整兼容性矩陣

行級鎖定VS分頁鎖定

鎖粒度越小,加鎖操做越頻繁,管理鎖帶來的開銷就越大。可是,鎖粒度越小,衝突率越小,併發性能會更好。每種類型的鎖定在針對不一樣類型的程序和處理方法時都會顯示出其獨特的優點,所以選中那種類型的鎖定,取決於應用程序和數據。

鎖升級

SQL Server在適當的時候會自動將行、鍵或者分頁級鎖升級爲粒度更粗的表級鎖。這種升級保護了系統資源(防止系統使用太多的內存在追蹤鎖),而且提升了效率。例如,在一個查詢獲取許多行級鎖後,鎖級別能夠升級爲表級鎖,由於這時獲取並持有一個單獨的表級鎖比持有許多行級鎖可能更有意義。

死鎖

當兩個事務都在等待獲取資源,可是因爲相互阻礙對方獲取資源致使沒有事務可以前進時就會發生死鎖。
 
 

行級版本控制

樂觀併發控制採用了一種稱爲行版本控制的新技術來保障事務。在使用樂觀鎖併發控制時會獲取排他鎖。樂觀併發和悲觀併發的區別在於樂觀併發中寫操做與讀操做之間不會互相阻塞。換句話說就是,當被請求資源當前擁有共享鎖時,申請排它鎖的事務不會被阻塞,相反,當被請求資源當前擁有排他鎖時,申請共享鎖的進程也不會被阻塞。

一旦啓用樂觀並反控制,SQL Server就使用tempdb數據庫來存儲全部已經修改過的記錄的副本,而且只要存在來自任意事務的訪問需求,就會繼續維持這些副本。當tempdb用來存儲被修改記錄的早期版本時,就其稱爲版本存儲區

行版本控制的實現

SQL Server引入了一種新的隔離級別:快照隔離以及一種新式的無阻塞風格的已提交讀隔離——已提交讀(快照)。這些基於版本控制的隔離級別容許讀者獲取行的一個先前已提交過的值而不會產生阻塞,這樣就提升了系統的併發能力。爲了使它起做用,SQL Server必須在行被修改或刪除時保留舊版本的記錄。若是在同一行上進行屢次更新,SQL Server就可能須要維護該行的多個早起版本。鑑於此,行版本控制有時也被稱爲多版併發控制。

當表或索引中的一行數據被更新時,SQL Server會用執行更新的那個事務的事務序列號來標記新的行。事務序列號是一個單調遞增的數字,在每一個SQL Server的實例中保證惟一。在更新一行數據時,以前的版本存放在版本存儲區內,而新的行包含一個指向版本存儲區中舊的行數據的指針。版本存儲區裏舊的行數據可能包含了指向更早版本的指針。一條行記錄的全部版本串接成一個鏈表。SQL Server可能須要沿着鏈表中的幾個指針才能到達一個正確的版本,只要有操做須要引用它們,行的版本就必須在版本存儲區內保存。

在應用程序使用默認的悲觀模型形成的併發性降低而不能使人滿意時,SQL Server能夠改用樂觀併發控制模型。在切換到基於樂觀版本控制的隔離級別以前,用戶必須仔細權衡使用新型併發模型的效果。處理須要額外的管理來爲版本存儲區監控tempdb之外,鑑於維護舊版本鎖帶來的額外工做量,版本控制還會下降更新操做的性能。即便當前沒有人在讀取數據,更新操做也得爲此買單。若是有使用行版本控制的讀操做,它們必須花費額外的開銷來遍歷鏈表指針,以找到須要的行數據的合適版本。

另外,因爲快照隔離的樂觀併發模型假定系統不會發生不少的更新衝突,若是用戶預見到在同一數據上的併發更新會產生競爭,就不該該選擇快照隔離級別。快照隔離級別可以使讀者不被寫者阻塞,可是併發的寫者仍然不被容許。在默認的悲觀模型中,第一個寫者會阻塞全部的後續寫者,但若是採用快照隔離,後續寫者實際上會接受到錯誤消息且應用程序須要從新提交初始請求。

基於快照的隔離級別

已提交讀快照隔離(RCSI)

已提交讀快照隔離是一種語句級的快照隔離,也就是任何查詢都能看到在語句開始那一刻最近提交過的數值。假設在啓用了RCSI的數據庫上有以下兩個事務,且在事務開始運行以前Product 922的ListPrice值是8.89

注意當時間爲2時,事務1所做出的修改還沒有提交,所以Product ID=922的行上仍然持有鎖。可是事務2不會被這個鎖阻塞住,它可以訪問該行數據上一次已提交的ListPrice值8.89。這仍然屬於已提交讀隔離級別(一個無阻塞的變種),因此不能防止「不可重複讀」。

RCSI最大的益處是能夠引入更好的併發性,由於讀者與寫者之間不會相互阻塞。可是寫者之間仍是會發生阻塞,所以標準的加鎖機制適用於所有的更新、刪除和插入操做。

快照隔離(SI)

SI提供了數據的一種事務一致性視圖。任何讀取操做都將獲得在事務開始那一刻最近已提交過的數據版本(對於RCSI,會獲得在語句開始那一刻最近已提交過的數據版本)。須要謹記的一個要點:事務並非從BEGIN TRAN語句開始的,對於SI來講,事務是在第一次訪問數據庫內任意數據的時候纔開始的。
 
儘管事務1已經提交了,事務2繼續返回它讀到的初始值8.99,直到事務2完成爲止。只有在事務2完成之後,該連接才能讀到ListPrice的新值。

更新衝突

兩種樂觀併發級別之間的重要區別在於:SI可能會形成潛在的更新衝突。

衝突發生是由於事務2在Quantity值爲324的時候開始,當這個值被事務1更新後,行版本324被存儲到版本存儲區內。事務2會在事務的持續時間內繼續讀取該行數據。若是兩個更新操做都被容許成功執行的話,就會產生經典的更新丟失情形。事務1增長了200個數量,而後事務2會在初始值上增長300個數量並存儲。由第一個事務增長的那200個產品就會完全丟失,SQL Server不會容許這樣的狀況發生。

當事務2開始嘗試執行更新時,並不會馬上獲得一個錯誤——僅僅是被阻塞。事務1在行上擁有一個排他鎖,所以事務2嘗試獲取排他鎖時會被阻塞。若是事務1回滾,那麼事務2就可以完成更新。但事務1最終被提交了,SQL Server檢測到一個衝突併產生錯誤。

衝突只可能發生在SI模式下,由於SI隔離級別是基於事務而不是基於語句的。若是上述例子在一個採用RCSI的數據庫中執行,事務2執行的更新語句不會使用該數據的原來值。當試圖讀取當前的Quantity值時,它會被阻塞住,而接着事務1完成時,它就能讀取更新過的Quantity將其做爲當前值並再增長300,沒有一個更新會丟失。

若是用戶選擇工做在SI模式下就須要注意可能發生的衝突,它們可以被減小到最低限度,可是如同死鎖同樣,用戶不能保證不發生衝突。用戶必須寫程序來合理地處理衝突,而且不能想固然地認爲更新已經成功了。若是衝突只是偶然發生,用戶可能須要將其做爲使用SI模式的部分代價考慮在內,但若是衝突太過頻繁,就須要額外措施來避免衝突。

3   參考文獻

 【01】http://blog.jobbole.com/104445/

4   版權

 

  • 感謝您的閱讀,如有不足之處,歡迎指教,共同窗習、共同進步。
  • 博主網址:http://www.cnblogs.com/wangjiming/。
  • 極少部分文章利用讀書、參考、引用、抄襲、複製和粘貼等多種方式整合而成的,大部分爲原創。
  • 如您喜歡,麻煩推薦一下;如您有新想法,歡迎提出,郵箱:2016177728@qq.com。
  • 能夠轉載該博客,但必須著名博客來源。
相關文章
相關標籤/搜索