如果沒有鎖定且多個用戶同時訪問一個數據庫,則當他們的事務同時使用相同的數據時可能會發生問題。並發問題包括:
例如,兩個編輯人員制作了同一文檔的電子復本。每個編輯人員獨立地更改其復本,然後保存更改後的復本,這樣就覆蓋了原始文檔。最後保存其更改復本的編輯人員覆蓋了第一個編輯人員所做的更改。如果在第一個編輯人員完成之後第二個編輯人員才能進行更改,則可以避免該問題。
當第二個事務選擇其它事務正在更新的行時,會發生未確認的相關性問題。第二個事務正在讀取的數據還沒有確認並且可能由更新此行的事務所更改。
例如,一個編輯人員正在更改電子文檔。在更改過程中,另一個編輯人員復制了該文檔(該復本包含到目前為止所做的全部更改)並將其分發給預期的用戶。此後,第一個編輯人員認為目前所做的更改是錯誤的,於是刪除了所做的編輯並保存了文檔。分發給用戶的文檔包含不再存在的編輯內容,並且這些編輯內容應認為從未存在過。如果在第一個編輯人員確定最終更改前任何人都不能讀取更改的文檔,則可以避免該問題。
當第二個事務多次訪問同一行而且每次讀取不同的數據時,會發生不一致的分析問題。不一致的分析與未確認的相關性類似,因為其它事務也是正在更改第二個事務正在讀取的數據。然而,在不一致的分析中,第二個事務讀取的數據是由已進行了更改的事務提交的。而且,不一致的分析涉及多次(兩次或更多)讀取同一行,而且每次信息都由其它事務更改;因而該行被非重復讀取。
例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重復。如果只有在作者全部完成編寫後編輯人員才可以讀取文檔,則可以避免該問題。
當對某行執行插入或刪除操作,而該行屬於某個事務正在讀取的行的范圍時,會發生幻像讀問題。事務第一次讀的行范圍顯示出其中一行已不復存在於第二次讀或後續讀中,因為該行已被其它事務刪除。同樣,由於其它事務的插入操作,事務的第二次或後續讀顯示有一行已不存在於原始讀中。
例如,一個編輯人員更改作者提交的文檔,但當生產部門將其更改內容合並到該文檔的主復本時,發現作者已將未編輯的新材料添加到該文檔中。如果在編輯人員和生產部門完成對原始文檔的處理之前,任何人都不能將新材料添加到文檔中,則可以避免該問題。
當鎖定用作並發控制機制時,它可以解決並發問題。這使所有事務得以在彼此完全隔離的環境中運行,但是任何時候都可以有多個正在運行的事務。
可串行性是通過運行一組並發事務達到的數據庫狀態,等同於這組事務按某種順序連續執行時所達到的數據庫狀態。
盡管可串行性對於事務確保數據庫中的數據在所有時間內的正確性相當重要,然而許多事務並不總是要求完全的隔離。例如,多個作者工作於同一本書的不同章節。新章節可以在任意時候提交到項目中。但是,對於已經編輯過的章節,沒有編輯人員的批准,作者不能對此章節進行任何更改。這樣,盡管有未編輯的新章節,但編輯人員仍可以確保在任意時間該書籍項目的正確性。編輯人員可以查看以前編輯的章節以及最近提交的章節。
事務准備接受不一致數據的級別稱為隔離級別。隔離級別是一個事務必須與其它事務進行隔離的程度。較低的隔離級別可以增加並發,但代價是降低數據的正確性。相反,較高的隔離級別可以確保數據的正確性,但可能對並發產生負面影響。應用程序要求的隔離級別確定了 SQL Server 使用的鎖定行為。
SQL-92 定義了下列四種隔離級別,SQL Server 支持所有這些隔離級別:
如果事務在可串行讀隔離級別上運行,則可以保證任何並發重疊事務均是串行的。
下面四種隔離級別允許不同類型的行為。
髒讀
不可重復讀取
幻像
未提交讀
是
是
是
提交讀
否
是
是
可重復讀
否
否
是
可串行讀
否
否
否
事務必須運行於可重復讀或更高的隔離級別以防止丟失更新。當兩個事務檢索相同的行,然後基於原檢索的值對行進行更新時,會發生丟失更新。如果兩個事務使用一個 UPDATE 語句更新行,並且不基於以前檢索的值進行更新,則在默認的提交讀隔離級別不會發生丟失更新。
三、問題解決的實現:
控制由連接發出的所有 Microsoft® SQL Server™ SELECT 語句的默認事務鎖定行為。
SET TRANSACTION ISOLATION LEVEL
{ READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
}
READ COMMITTED
指定在讀取數據時控制共享鎖以避免髒讀,但數據可在事務結束前更改,從而產生不可重復讀取或幻像數據。該選項是 SQL Server 的默認值。
READ UNCOMMITTED
執行髒讀或 0 級隔離鎖定,這表示不發出共享鎖,也不接受排它鎖。當設置該選項時,可以對數據執行未提交讀或髒讀;在事務結束前可以更改數據內的數值,行也可以出現在數據集中或從數據集消失。該選項的作用與在事務內所有語句中的所有表上設置 NOLOCK 相同。這是四個隔離級別中限制最小的級別。
REPEATABLE READ
鎖定查詢中使用的所有數據以防止其他用戶更新數據,但是其他用戶可以將新的幻像行插入數據集,且幻像行包括在當前事務的後續讀取中。因為並發低於默認隔離級別,所以應只在必要時才使用該選項。
SERIALIZABLE
在數據集上放置一個范圍鎖,以防止其他用戶在事務完成之前更新數據集或將行插入數據集內。這是四個隔離級別中限制最大的級別。因為並發級別較低,所以應只在必要時才使用該選項。該選項的作用與在事務內所有 SELECT 語句中的所有表上設置 HOLDLOCK 相同。
一次只能設置這些選項中的一個,而且設置的選項將一直對那個連接保持有效,直到顯式更改該選項為止。這是默認行為,除非在語句的 FROM 子句中在表級上指定優化選項。
SET TRANSACTION ISOLATION LEVEL 的設置是在執行或運行時設置,而不是在分析時設置。
下例為會話設置 TRANSACTION ISOLATION LEVEL。對於每個後續 Transact-SQL 語句,SQL Server 將所有共享鎖一直控制到事務結束為止。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
BEGIN TRANSACTION
SELECT * FROM publishers
SELECT * FROM authors
...
COMMIT TRANSACTION
默認情況下,Microsoft® SQL Server™ 2000 在 READ COMMITTED 的一個隔離級別上操作。但是,應用程序可能必須運行於不同的隔離級別。若要在應用程序中使用更嚴格或較寬松的隔離級別,可以通過使用 SET TRANSACTION ISOLATION LEVEL 語句設置會話的隔離級別,來自定義整個會話的鎖定。
指定隔離級別後,SQL Server 會話中所有 SELECT 語句的鎖定行為都運行於該隔離級別上,並一直保持有效直到會話終止或者將隔離級別設置為另一個級別。例如,若要設置事務隔離級別為可串行讀,以確保並發事務不能在 authors 表中插入幻像行,請執行:
USE pubs
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
SELECT au_lname FROM authors
說明 如果必要,可以通過指定表級鎖定提示來替代單個 SELECT 語句的隔離級別。指定表級鎖定提示不會影響會話中的其它語句。建議僅在絕對必要時才使用表級鎖定提示更改默認的鎖定行為。
若要確定當前設置的事務隔離級別,請使用 DBCC USEROPTIONS 語句,例如:
USE pubs
GO
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
DBCC USEROPTIONS
GO
Set Option
Value
Textsize
4096
Language
us_english
Dateformat
mdy
Datefirst
7
isolation level
repeatable read
(5 rows affected)
DBCC execution completed. If DBCC printed error messages, see your System Administrator.
隔離屬性是 ACID 的四個屬性之一,邏輯工作單元必須具備這四個屬性才能稱為事務。該屬性能夠使事務免受其它並發事務所執行的更新的影響。每個事務的隔離級別實際上都是可以自定義的。
Microsoft® SQL Server™ 支持 SQL-92 中定義的事務隔離級別。設置事務隔離級別雖然使程序員承擔了某些完整性問題所帶來的風險,但可以換取對數據更大的並發訪問權。與以前的隔離級別相比,每個隔離級別都提供了更大的隔離性,但這是通過在更長的時間內占用更多限制鎖換來的。事務隔離級別有:
您正在看的SQLserver教程是:Sqlserver2000中的並發問題。READ UNCOMMITTED可以使用 Transact-SQL 或通過數據庫 API 來設置事務隔離級別:
Transact-SQL
Transact-SQL 腳本和 DB-Library 應用程序使用 SET TRANSACTION ISOLATION LEVEL 語句。
ADO
ADO 應用程序將 Connection 對象的 IsolationLevel 屬性設置為 adXactReadUncommitted、adXactReadCommitted、adXactRepeatableRead 或 adXactReadSerializable。
OLE DB
OLE DB 應用程序調用 ITransactionLocal::StartTransaction,其中 isoLevel 設置為 ISOLATIONLEVEL_READUNCOMMITTED、ISOLATIONLEVEL_READCOMMITTED、ISOLATIONLEVEL_REPEATABLEREAD 或 ISOLATIONLEVEL_SERIALIZABLE。
ODBC
ODBC 應用程序調用 SQLSetConnectAttr,其中 Attribute 設置為 SQL_ATTR_TXN_ISOLATION,ValuePtr 設置為 SQL_TXN_READ_UNCOMMITTED、SQL_TXN_READ_COMMITTED、SQL_TXN_REPEATABLE_READ 或 SQL_TXN_SERIALIZABLE。
參考<<sqlserver2000幫助文件>>