| 導購 | 订阅 | 在线投稿
分享
 
 
 

當多個用戶訪問同一數據庫時會發生的現象

來源:互聯網  2008-06-03 06:17:50  評論

使用單用戶數據庫時,每個事務都是順序執行的,而不必應付與其它事務的沖突。但是,在多用戶數據庫環境下,多個事務可以同步執行,並且每個事務都有可能與其它正在運行的事務發生沖突。在多用戶環境下,如果不將事務彼此隔離開來,就會發生四種現象:

丟失更新:

這種事件發生在兩個事務讀取和嘗試更新同一數據時,其中一個更新會丟失。例如:事務 1 和事務 2 讀取同一行數據,並都根據所讀取的數據計算出該行的新值。如果事務 1 用其新值更新該行以後,事務 2 又更新了同一行,則事務 1 所執行的更新操作就丟失了。由于設計的方法,DB2 通用數據庫不允許發生此類現象。

髒讀:

當事務讀取尚未提交的數據時,就會發生這種事件。例如:事務 1 更改了一行數據,而事務 2 在事務 1 提交更改之前讀取了已更改的行。如果事務 1 回滾該更改,則事務 2 就會讀取被認爲是不曾存在的數據。

不可重複的讀:

當一個事務兩次讀取同一行數據,但每次獲得不同的數據值時,就會發生這種事件。例如:事務 1 讀取了一行數據,而事務 2 在更改或刪除該行後提交了更改。當事務 1 嘗試再次讀取該行時,它會檢索到不同的數據值(如果該行已經被更新的話),或發現該行不複存在了(如果該行被刪除的話)。

幻像:

當最初沒有看到某個與搜索條件匹配的數據行,而在稍後的讀操作中又看到該行時,就會發生這種事件。例如:事務 1 讀取滿足某個搜索條件的一組數據行,而事務 2 插入了與事務 1 搜索條件匹配的新行。如果事務 1 再次執行産生原先行集的查詢,則會檢索到不同的行集。

維護數據庫一致性和數據完整性,但又允許多個應用程序同時訪問同一數據,這樣的特性稱爲並發性。DB2 通用數據庫嘗試用來強制執行並發性的方法之一是通過使用隔離級別,它決定在第一個事務訪問數據時,如何對其它事務鎖定或隔離該事務所使用的數據。DB2 通用數據庫使用下列隔離級別來強制執行並發性:

可重複的讀(Repeatable Read)

讀穩定性(Read Stability)

遊標穩定性(Cursor Stability)

未提交的讀(Uncommitted Read)

我們將在接下來依次討論每種級別。

「可重複的讀」隔離級別

當使用可重複的讀隔離級別時,在單個事務執行期間鎖定該事務引用的所有行。使用這種隔離級別時,同一事務多次發出的同一個 SELECT 語句將始終産生同一結果;丟失更新、髒讀、不可重複的讀、幻像都不會發生。

使用可重複的讀隔離級別的事務可以多次檢索同一行集,並可以對它們執行任意次操作,直到由提交或回滾操作終止事務;不允許其它事務執行插入、更新或刪除操作,因爲這些操作會在隔離事務存在期間影響正在被使用的行集。爲了確保在「可重複的讀」隔離級別下運行的事務所訪問的數據不會受其它事務的負面影響,所以鎖定了該隔離事務所引用的每個行 — 而不是僅鎖定被實際檢索和/或修改的那些行。因此,如果一個事務掃描了 1000 行但只檢索 10 行,則所掃描的 1000 行(而不僅是被檢索的 10 行)都會被鎖定。

那麽在現實環境中這個隔離級別是如何工作的呢?假定您擁有一家大型旅館,並有一個網站,該網站按「先到先服務」的原則接受客戶的房間預訂。如果您的旅館預訂應用程序是在「可重複的讀」隔離級別下運行的,當客戶檢索某個日期段內的所有可用房間列表時,您將無法更改那些房間在指定日期範圍內的費用,而其他客戶也將無法進行或取消將會更改該列表的預訂,直到生成該列表的事務終止爲止。(對于第一個客戶的查詢所指定範圍之外的任何房間,您都可以更改房價,其他客戶也都可以進行或取消房間預訂。)

「讀穩定性」隔離級別

當使用讀穩定性隔離級別時,在單個事務執行期間,會鎖定該事務所檢索的所有行。當使用這種隔離級別時,直到隔離事務終止之前,其它事務不能更改隔離事務讀取的所有行。此外,其它事務對其它行所作的更改,在提交之前對于運行在「讀穩定性」隔離級別下的事務而言是不可見的。因此,當使用「讀穩定性」隔離級別時,在同一事務中多次發出 SELECT 語句可能會産生不同的結果。丟失更新、髒讀和不可重複的讀都不會發生;但是,有可能出現幻像。

使用「可重複的讀」隔離級別時,隔離事務引用的每一行都被鎖定;但是,在「讀穩定性」隔離級別下,只鎖定隔離事務實際檢索和/或修改的行。因此,如果一個事務掃描了 1000 行但只檢索 10 行,則只有被檢索到的 10 行(而不是所掃描的 1000 行)被鎖定。

那麽,這種隔離級別會如何改變旅館預訂應用程序的工作方式呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表時,您可以更改旅館中任何房間的房價,而其他客戶也可以取消在第一個客戶的查詢所指定的日期段內所保留房間的預訂。因此,如果在終止提交查詢的事務之前再次生成列表,則産生的新列表中有可能包含新的房價或第一次産生列表時不可用的房間。

「遊標穩定性」隔離級別

當使用遊標穩定性隔離級別時,只要隔離事務所用的遊標定位在某一行上,就會鎖定該遊標所引用的這一行。所獲取的鎖一直有效,直到遊標重定位(通常通過調用 FETCH 語句)或隔離事務終止爲止。因此,當使用這種隔離級別時,在同一事務中多次發出 SELECT 語句可能會産生不同的結果。丟失更新和髒讀不會發生;但有可能出現不可重複的讀和幻像。

當使用「遊標穩定性」隔離級別的事務通過可更新遊標從表中檢索行時,在遊標定位在該行上時,其它事務不能更新或刪除該行。但是,如果被鎖定的行本身不是用索引訪問的,那麽其它事務可以將新的行添加到表,並對位于被鎖定行前後的行進行更新和/或刪除操作。此外,如果隔離事務修改了它檢索到的任何行,那麽在隔離事務終止之前,即使在遊標不再位于這個被修改的行,其它事務不能更新或刪除該行。

其它事務在其它行上進行的更改,在提交之前對于使用「遊標穩定性」隔離級別的事務是不可見的。缺省情況下,大多數事務都使用「遊標穩定性」隔離級別。

這種隔離級別對旅館預訂應用程序有什麽影響呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表,然後查看關于所産生的列表上每個房間的信息時(每次查看一個房間),您可以更改旅館中任何房間的房價,而其他客戶可以對任何日期段的任何房間進行或取消預訂;唯一的例外是第一個客戶當前正在查看的房間。當第一個客戶查看列表中另一個房間的信息時,對于這個新房間也是一樣;您現在可以更改第一個客戶剛才查看的房間的房價,其他客戶也可以預訂該房間,但不能對第一個客戶當前正在查看的房間進行這些操作。

「未提交的讀」隔離級別

在使用未提交的讀隔離級別的情況中,當單個事務檢索行時,僅當另一個事務試圖刪除或更改被檢索的行所在的表時,才會在單個事務期間鎖定這些行。因爲在使用這種隔離級別時,行通常保持未鎖定狀態,所以丟失更新、髒讀、不可重複的讀和幻像都可能會發生。

在大多數情況下,其它事務對行所作的更改,在提交或回滾之前對于使用「未提交的讀」隔離級別的事務是可見的。但是,此類事務不能看見或訪問其它事務所創建的表、視圖或索引,直到那些事務被提交爲止。類似地,如果其它事務刪除了現有的表、視圖或索引,使用「未提交的讀」隔離級別的事務僅當進行刪除操作的事務終止時才能了解這一情況。這種行爲有一個例外:當運行在「未提交的讀」隔離級別下的事務使用可更新遊標時,該事務的行爲和在「遊標穩定性」隔離級別下運行一樣,並應用「遊標穩定性」隔離級別的約束。

「未提交的讀」隔離級別通常用于那些訪問只讀表的事務和/或某些執行 SELECT 語句的事務,這些語句對其它事務的未提交數據沒有負面效果。

那麽這種隔離級別對旅館預訂應用程序有什麽影響呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表時,您可以更改旅館中任何房間的房價,而其它客戶也可以對任何日期段內的任何房間進行或取消預訂。此外,如果其它客戶取消了預訂,即使他們還沒有終止其事務並將那些取消提交到數據庫,所生成的列表就可以包含這些取消預訂的房間了。

指定隔離級別

盡管隔離級別是控制如何爲事務鎖定資源的,但實際上是在應用程序級別指定它們的。對于嵌入式 SQL 應用程序,是在預編譯時或將應用程序綁定到數據庫時指定要使用的隔離級別。在大多數情況下,應用程序的隔離級別是用受支持的編譯語言(如 C 或 C++)編寫的,通過 PRECOMPILE PROGRAM 和 BIND 命令/API 的 ISOLATION 選項來設置隔離級別。對于調用級接口(CLI)應用程序,所用的隔離級別是在應用程序運行時通過調用指定了 SQL_ATTR_TXN_ISOLATION 連接屬性的 SQLSetConnectAttr() 函數進行設置的。也可以通過指定TXNISOLATION 關鍵字的值來設置 CLI 應用程序的隔離級別,該關鍵字位于 db2cli.ini 配置文件中。對于 JDBC 和 SQLJ 應用程序,隔離級別是在應用程序運行時通過調用駐留在 java.sql 連接接口中的 setTransactionIsolation() 方法設置的。

當沒有指定隔離級別時,則缺省地使用「遊標穩定性」隔離級別。對于從命令行處理器(CLP)執行的命令和腳本以及嵌入式 SQL、CLI、JDBC 和 SQLJ 應用程序都是如此。因此,也可以指定從 CLP 運行的命令和腳本所用的隔離級別;在這種情況下,所用的隔離級別是通過在建立與數據庫的連接之前在 CLP 中執行 CHANGE ISOLATION 命令設置的。

選擇適當的隔離級別

選擇用于事務的適當隔離級別是非常重要的。隔離級別不僅影響數據庫如何很好地支持並發性;而且影響包含該事務的應用程序的整體性能。這是因爲獲取和釋放鎖所需的資源因隔離級別而異。

通常,使用的隔離級別越嚴格,對並發性提供的支持就越少,而整體性能可能會越低,因爲要獲取並占有更多的資源。但是,當您確定將要使用的最佳隔離級別時,應該通過確定哪些現象可接受而哪些現象不可接受來進行決策。下列推斷可以用來幫助您確定在特定環境中使用哪種隔離級別:

如果您正在只讀數據庫上執行查詢,或者正在執行查詢而不考慮是否有未提交的數據值返回,則使用「未提交的讀」隔離級別。(需要是只讀事務 — 不需要較高的數據穩定性。)

如果您希望在不看見未提交數據值的情況下獲得最大的並發性,則使用「遊標穩定性」隔離級別。(需要是讀/寫事務 — 不需要較高的數據穩定性。)

如果您希望獲得並發性,並希望限定的行在單個事務執行期間保持穩定,則使用「讀穩定性」隔離級別。(需要是只讀或讀/寫事務 — 需要較高的數據穩定性。)

如果您正在執行查詢,並且不希望看到對産生的結果數據集進行更改,則使用「可重複的讀」隔離級別。(需要是只讀事務 — 需要極高的數據穩定性。)

使用單用戶數據庫時,每個事務都是順序執行的,而不必應付與其它事務的沖突。但是,在多用戶數據庫環境下,多個事務可以同步執行,並且每個事務都有可能與其它正在運行的事務發生沖突。在多用戶環境下,如果不將事務彼此隔離開來,就會發生四種現象: 丟失更新: 這種事件發生在兩個事務讀取和嘗試更新同一數據時,其中一個更新會丟失。例如:事務 1 和事務 2 讀取同一行數據,並都根據所讀取的數據計算出該行的新值。如果事務 1 用其新值更新該行以後,事務 2 又更新了同一行,則事務 1 所執行的更新操作就丟失了。由于設計的方法,DB2 通用數據庫不允許發生此類現象。 髒讀: 當事務讀取尚未提交的數據時,就會發生這種事件。例如:事務 1 更改了一行數據,而事務 2 在事務 1 提交更改之前讀取了已更改的行。如果事務 1 回滾該更改,則事務 2 就會讀取被認爲是不曾存在的數據。 不可重複的讀: 當一個事務兩次讀取同一行數據,但每次獲得不同的數據值時,就會發生這種事件。例如:事務 1 讀取了一行數據,而事務 2 在更改或刪除該行後提交了更改。當事務 1 嘗試再次讀取該行時,它會檢索到不同的數據值(如果該行已經被更新的話),或發現該行不複存在了(如果該行被刪除的話)。 幻像: 當最初沒有看到某個與搜索條件匹配的數據行,而在稍後的讀操作中又看到該行時,就會發生這種事件。例如:事務 1 讀取滿足某個搜索條件的一組數據行,而事務 2 插入了與事務 1 搜索條件匹配的新行。如果事務 1 再次執行産生原先行集的查詢,則會檢索到不同的行集。 維護數據庫一致性和數據完整性,但又允許多個應用程序同時訪問同一數據,這樣的特性稱爲並發性。DB2 通用數據庫嘗試用來強制執行並發性的方法之一是通過使用隔離級別,它決定在第一個事務訪問數據時,如何對其它事務鎖定或隔離該事務所使用的數據。DB2 通用數據庫使用下列隔離級別來強制執行並發性: 可重複的讀(Repeatable Read) 讀穩定性(Read Stability) 遊標穩定性(Cursor Stability) 未提交的讀(Uncommitted Read) 我們將在接下來依次討論每種級別。 「可重複的讀」隔離級別 當使用可重複的讀隔離級別時,在單個事務執行期間鎖定該事務引用的所有行。使用這種隔離級別時,同一事務多次發出的同一個 SELECT 語句將始終産生同一結果;丟失更新、髒讀、不可重複的讀、幻像都不會發生。 使用可重複的讀隔離級別的事務可以多次檢索同一行集,並可以對它們執行任意次操作,直到由提交或回滾操作終止事務;不允許其它事務執行插入、更新或刪除操作,因爲這些操作會在隔離事務存在期間影響正在被使用的行集。爲了確保在「可重複的讀」隔離級別下運行的事務所訪問的數據不會受其它事務的負面影響,所以鎖定了該隔離事務所引用的每個行 — 而不是僅鎖定被實際檢索和/或修改的那些行。因此,如果一個事務掃描了 1000 行但只檢索 10 行,則所掃描的 1000 行(而不僅是被檢索的 10 行)都會被鎖定。 那麽在現實環境中這個隔離級別是如何工作的呢?假定您擁有一家大型旅館,並有一個網站,該網站按「先到先服務」的原則接受客戶的房間預訂。如果您的旅館預訂應用程序是在「可重複的讀」隔離級別下運行的,當客戶檢索某個日期段內的所有可用房間列表時,您將無法更改那些房間在指定日期範圍內的費用,而其他客戶也將無法進行或取消將會更改該列表的預訂,直到生成該列表的事務終止爲止。(對于第一個客戶的查詢所指定範圍之外的任何房間,您都可以更改房價,其他客戶也都可以進行或取消房間預訂。) 「讀穩定性」隔離級別 當使用讀穩定性隔離級別時,在單個事務執行期間,會鎖定該事務所檢索的所有行。當使用這種隔離級別時,直到隔離事務終止之前,其它事務不能更改隔離事務讀取的所有行。此外,其它事務對其它行所作的更改,在提交之前對于運行在「讀穩定性」隔離級別下的事務而言是不可見的。因此,當使用「讀穩定性」隔離級別時,在同一事務中多次發出 SELECT 語句可能會産生不同的結果。丟失更新、髒讀和不可重複的讀都不會發生;但是,有可能出現幻像。 使用「可重複的讀」隔離級別時,隔離事務引用的每一行都被鎖定;但是,在「讀穩定性」隔離級別下,只鎖定隔離事務實際檢索和/或修改的行。因此,如果一個事務掃描了 1000 行但只檢索 10 行,則只有被檢索到的 10 行(而不是所掃描的 1000 行)被鎖定。 那麽,這種隔離級別會如何改變旅館預訂應用程序的工作方式呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表時,您可以更改旅館中任何房間的房價,而其他客戶也可以取消在第一個客戶的查詢所指定的日期段內所保留房間的預訂。因此,如果在終止提交查詢的事務之前再次生成列表,則産生的新列表中有可能包含新的房價或第一次産生列表時不可用的房間。 「遊標穩定性」隔離級別 當使用遊標穩定性隔離級別時,只要隔離事務所用的遊標定位在某一行上,就會鎖定該遊標所引用的這一行。所獲取的鎖一直有效,直到遊標重定位(通常通過調用 FETCH 語句)或隔離事務終止爲止。因此,當使用這種隔離級別時,在同一事務中多次發出 SELECT 語句可能會産生不同的結果。丟失更新和髒讀不會發生;但有可能出現不可重複的讀和幻像。 當使用「遊標穩定性」隔離級別的事務通過可更新遊標從表中檢索行時,在遊標定位在該行上時,其它事務不能更新或刪除該行。但是,如果被鎖定的行本身不是用索引訪問的,那麽其它事務可以將新的行添加到表,並對位于被鎖定行前後的行進行更新和/或刪除操作。此外,如果隔離事務修改了它檢索到的任何行,那麽在隔離事務終止之前,即使在遊標不再位于這個被修改的行,其它事務不能更新或刪除該行。 其它事務在其它行上進行的更改,在提交之前對于使用「遊標穩定性」隔離級別的事務是不可見的。缺省情況下,大多數事務都使用「遊標穩定性」隔離級別。 這種隔離級別對旅館預訂應用程序有什麽影響呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表,然後查看關于所産生的列表上每個房間的信息時(每次查看一個房間),您可以更改旅館中任何房間的房價,而其他客戶可以對任何日期段的任何房間進行或取消預訂;唯一的例外是第一個客戶當前正在查看的房間。當第一個客戶查看列表中另一個房間的信息時,對于這個新房間也是一樣;您現在可以更改第一個客戶剛才查看的房間的房價,其他客戶也可以預訂該房間,但不能對第一個客戶當前正在查看的房間進行這些操作。 「未提交的讀」隔離級別 在使用未提交的讀隔離級別的情況中,當單個事務檢索行時,僅當另一個事務試圖刪除或更改被檢索的行所在的表時,才會在單個事務期間鎖定這些行。因爲在使用這種隔離級別時,行通常保持未鎖定狀態,所以丟失更新、髒讀、不可重複的讀和幻像都可能會發生。 在大多數情況下,其它事務對行所作的更改,在提交或回滾之前對于使用「未提交的讀」隔離級別的事務是可見的。但是,此類事務不能看見或訪問其它事務所創建的表、視圖或索引,直到那些事務被提交爲止。類似地,如果其它事務刪除了現有的表、視圖或索引,使用「未提交的讀」隔離級別的事務僅當進行刪除操作的事務終止時才能了解這一情況。這種行爲有一個例外:當運行在「未提交的讀」隔離級別下的事務使用可更新遊標時,該事務的行爲和在「遊標穩定性」隔離級別下運行一樣,並應用「遊標穩定性」隔離級別的約束。 「未提交的讀」隔離級別通常用于那些訪問只讀表的事務和/或某些執行 SELECT 語句的事務,這些語句對其它事務的未提交數據沒有負面效果。 那麽這種隔離級別對旅館預訂應用程序有什麽影響呢?現在,當一個客戶檢索某個日期段內的所有可用房間列表時,您可以更改旅館中任何房間的房價,而其它客戶也可以對任何日期段內的任何房間進行或取消預訂。此外,如果其它客戶取消了預訂,即使他們還沒有終止其事務並將那些取消提交到數據庫,所生成的列表就可以包含這些取消預訂的房間了。 指定隔離級別 盡管隔離級別是控制如何爲事務鎖定資源的,但實際上是在應用程序級別指定它們的。對于嵌入式 SQL 應用程序,是在預編譯時或將應用程序綁定到數據庫時指定要使用的隔離級別。在大多數情況下,應用程序的隔離級別是用受支持的編譯語言(如 C 或 C++)編寫的,通過 PRECOMPILE PROGRAM 和 BIND 命令/API 的 ISOLATION 選項來設置隔離級別。對于調用級接口(CLI)應用程序,所用的隔離級別是在應用程序運行時通過調用指定了 SQL_ATTR_TXN_ISOLATION 連接屬性的 SQLSetConnectAttr() 函數進行設置的。也可以通過指定TXNISOLATION 關鍵字的值來設置 CLI 應用程序的隔離級別,該關鍵字位于 db2cli.ini 配置文件中。對于 JDBC 和 SQLJ 應用程序,隔離級別是在應用程序運行時通過調用駐留在 java.sql 連接接口中的 setTransactionIsolation() 方法設置的。 當沒有指定隔離級別時,則缺省地使用「遊標穩定性」隔離級別。對于從命令行處理器(CLP)執行的命令和腳本以及嵌入式 SQL、CLI、JDBC 和 SQLJ 應用程序都是如此。因此,也可以指定從 CLP 運行的命令和腳本所用的隔離級別;在這種情況下,所用的隔離級別是通過在建立與數據庫的連接之前在 CLP 中執行 CHANGE ISOLATION 命令設置的。 選擇適當的隔離級別 選擇用于事務的適當隔離級別是非常重要的。隔離級別不僅影響數據庫如何很好地支持並發性;而且影響包含該事務的應用程序的整體性能。這是因爲獲取和釋放鎖所需的資源因隔離級別而異。 通常,使用的隔離級別越嚴格,對並發性提供的支持就越少,而整體性能可能會越低,因爲要獲取並占有更多的資源。但是,當您確定將要使用的最佳隔離級別時,應該通過確定哪些現象可接受而哪些現象不可接受來進行決策。下列推斷可以用來幫助您確定在特定環境中使用哪種隔離級別: 如果您正在只讀數據庫上執行查詢,或者正在執行查詢而不考慮是否有未提交的數據值返回,則使用「未提交的讀」隔離級別。(需要是只讀事務 — 不需要較高的數據穩定性。) 如果您希望在不看見未提交數據值的情況下獲得最大的並發性,則使用「遊標穩定性」隔離級別。(需要是讀/寫事務 — 不需要較高的數據穩定性。) 如果您希望獲得並發性,並希望限定的行在單個事務執行期間保持穩定,則使用「讀穩定性」隔離級別。(需要是只讀或讀/寫事務 — 需要較高的數據穩定性。) 如果您正在執行查詢,並且不希望看到對産生的結果數據集進行更改,則使用「可重複的讀」隔離級別。(需要是只讀事務 — 需要極高的數據穩定性。)
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有