




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第12章事務(wù)處理、并發(fā)控制和游標(biāo)SQLServer是一個(gè)多任務(wù)多用戶的數(shù)據(jù)庫系統(tǒng),在同一個(gè)時(shí)間內(nèi)可能有多個(gè)操作同時(shí)并發(fā)訪問數(shù)據(jù)庫。當(dāng)多用戶對(duì)數(shù)據(jù)庫并發(fā)訪問時(shí),SQLServer使用鎖和事務(wù)的機(jī)制來保證數(shù)據(jù)的一致性。本章講解事務(wù)、鎖、并發(fā)控制等相關(guān)的知識(shí)。本章的學(xué)習(xí)目標(biāo):理解并發(fā)、事務(wù)、鎖的根本概念掌握并發(fā)控制、加鎖、解鎖和事務(wù)操作12.1事務(wù)事務(wù)和存儲(chǔ)過程類似,由一系列T-SQL語句組成,是SQLServer系統(tǒng)的執(zhí)行單元。本節(jié)主要介紹SQLServer中事務(wù)的概念,以及事務(wù)的創(chuàng)立、使用。12.1.1事務(wù)概述事務(wù)由作為一個(gè)邏輯工作單元〔包〕執(zhí)行的單個(gè)sql語句或一組sql語句組成。事務(wù)是單個(gè)工作單元,通過事務(wù)可以將對(duì)數(shù)據(jù)庫數(shù)據(jù)的多個(gè)操作合并為單個(gè)工作單元。如果某一事務(wù)成功,那么在該事務(wù)中進(jìn)行的所有數(shù)據(jù)修改均會(huì)提交,成為數(shù)據(jù)庫中的永久組成局部。如果事務(wù)遇到錯(cuò)誤且必須取消或回滾,那么所有數(shù)據(jù)修改均被去除,對(duì)數(shù)據(jù)庫的所有更新都回滾到其事務(wù)前的狀態(tài)。比方,我們?nèi)ャy行轉(zhuǎn)賬,操作可以分為下面兩個(gè)環(huán)節(jié):(1)從第一個(gè)賬戶劃出款項(xiàng)。(2)將款項(xiàng)存入第二個(gè)賬戶。整個(gè)交易過程,可以看作是一個(gè)事務(wù),成功那么全部成功,失敗那么需要全部撤消,這樣可以防止當(dāng)操作的中間環(huán)節(jié)出現(xiàn)問題時(shí),產(chǎn)生數(shù)據(jù)不一致的問題。數(shù)據(jù)庫事務(wù)是一個(gè)邏輯上的劃分,有的時(shí)候并不是很明顯,它可以是一個(gè)操作步驟,也可以是多個(gè)操作步驟。我們可以這樣理解數(shù)據(jù)庫事務(wù):對(duì)數(shù)據(jù)庫所做的一系列修改,在修改正程中,暫時(shí)不寫入數(shù)據(jù)庫,而是緩存起來,用戶在自己的終端可以預(yù)覽變化,直到全部修改完成,并經(jīng)過檢查確認(rèn)無誤后,一次性提交并寫入數(shù)據(jù)庫,在提交之前,必要的話所做的修改都可以取消。提交之后,就不能撤銷,提交成功后其它用戶才可以通過查詢?yōu)g覽數(shù)據(jù)的變化。以事務(wù)的方式對(duì)數(shù)據(jù)庫進(jìn)行訪問,有如下的優(yōu)點(diǎn):把邏輯相關(guān)的操作分成了一個(gè)組;在數(shù)據(jù)永久改變前,可以預(yù)覽數(shù)據(jù)變化;能夠保證數(shù)據(jù)的讀一致性。12.1.2事務(wù)的特性事務(wù)是作為單個(gè)邏輯工作單元執(zhí)行的一系列操作。一個(gè)邏輯工作單元必須有四個(gè)屬性,即原子性、一致性、隔離性和持久性,簡稱ACID屬性,只有這樣才能成為一個(gè)事務(wù)。事務(wù)的特性如下:〔1〕原子性(Atomic):指整個(gè)數(shù)據(jù)庫事務(wù)是不可分割的工作單位。事務(wù)中包括的諸操作要么都做,要么都不做〔2〕一致性(Consistency):指數(shù)據(jù)庫事務(wù)不能破壞關(guān)系數(shù)據(jù)的完整性以及業(yè)務(wù)邏輯的一致性。事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。一致性狀態(tài):數(shù)據(jù)庫中只包含成功事務(wù)提交的結(jié)果不一致狀態(tài):數(shù)據(jù)庫中包含失敗事務(wù)的結(jié)果〔3〕隔離性(Isolation):指的是在并發(fā)環(huán)境中,當(dāng)不同的事務(wù)同時(shí)操作相同的數(shù)據(jù)時(shí),每個(gè)事務(wù)都有各自的完整數(shù)據(jù)空間,一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)其它并發(fā)事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾?!?〕持久性(Durability):指的是只要事務(wù)成功結(jié)束,它對(duì)數(shù)據(jù)庫所做的更改就必須永久保存下來。接下來的其它操作或故障不應(yīng)該對(duì)其執(zhí)行結(jié)果有任何影響。事務(wù)的這種機(jī)制保證了一個(gè)事務(wù)或者提交后成功執(zhí)行,或者失敗回滾,二者必居其一,因此,事務(wù)對(duì)數(shù)據(jù)的修改具有可恢復(fù)性,即當(dāng)事務(wù)失敗時(shí),它對(duì)數(shù)據(jù)的修改都會(huì)恢復(fù)到該事務(wù)執(zhí)行前的狀態(tài)。而使用一般的批處理,那么有可能出現(xiàn)有的語句被執(zhí)行,而另一些語句沒有被執(zhí)行的情況,從而有可能造成數(shù)據(jù)不一致。數(shù)據(jù)庫采用日志來保證事務(wù)的原子性,一致性和持久性,日志記錄了事務(wù)對(duì)數(shù)據(jù)庫所做的更新,如果某個(gè)事務(wù)在執(zhí)行過程中發(fā)生錯(cuò)誤,就可以根據(jù)日志,撤銷事務(wù)對(duì)數(shù)據(jù)庫已做的更改,使數(shù)據(jù)庫退回到執(zhí)行事務(wù)前的初始狀態(tài)。事務(wù)開始之后,事務(wù)所有的操作都陸續(xù)寫到事務(wù)日志中。這些任務(wù)操作在事務(wù)日志中記錄一個(gè)標(biāo)志,用于表示執(zhí)行了這種操作,當(dāng)取消這種事務(wù)時(shí),系統(tǒng)自動(dòng)執(zhí)行這種操作的反操作,保證系統(tǒng)的一致性。系統(tǒng)自動(dòng)生成一個(gè)檢查點(diǎn)機(jī)制,這個(gè)檢查點(diǎn)周期地發(fā)生。檢查點(diǎn)的周期是系統(tǒng)根據(jù)用戶定義的時(shí)間間隔和系統(tǒng)活動(dòng)的頻度由系統(tǒng)自動(dòng)計(jì)算出來的時(shí)間間隔。檢查點(diǎn)周期地檢查事務(wù)日志,如果在事務(wù)日志中,事務(wù)全部完成,那么檢查點(diǎn)將事務(wù)提交到數(shù)據(jù)庫中,并且在事務(wù)日志中做一個(gè)檢查點(diǎn)提交標(biāo)記。如果在事務(wù)日志中,事務(wù)沒有完成,那么檢查點(diǎn)將事務(wù)日志中的事務(wù)不提交到數(shù)據(jù)庫中,并且在事務(wù)日志中做一個(gè)檢查點(diǎn)未提交標(biāo)記。12.1.3指定和強(qiáng)制事務(wù)SQL程序員要負(fù)責(zé)啟動(dòng)和結(jié)束事務(wù),同時(shí)強(qiáng)制保持?jǐn)?shù)據(jù)的邏輯一致性。程序員必須定義數(shù)據(jù)修改的順序,使數(shù)據(jù)相對(duì)于其組織的業(yè)務(wù)規(guī)那么保持一致。程序員將這些修改語句包括到一個(gè)事務(wù)中,使SQLServer數(shù)據(jù)庫引擎能夠強(qiáng)制該事務(wù)的物理完整性。企業(yè)數(shù)據(jù)庫系統(tǒng)〔如數(shù)據(jù)庫引擎實(shí)例〕有責(zé)任提供一種機(jī)制,保證每個(gè)事務(wù)的物理完整性。數(shù)據(jù)庫引擎提供:〔1〕鎖定設(shè)備,使事務(wù)保持隔離;〔2〕記錄設(shè)備,保證事務(wù)的持久性。即使效勞器硬件、操作系統(tǒng)或數(shù)據(jù)庫引擎實(shí)例自身出現(xiàn)故障,該實(shí)例也可以在重新啟動(dòng)時(shí)使用事務(wù)日志,將所有未完成的事務(wù)自動(dòng)地回滾到系統(tǒng)出現(xiàn)故障的點(diǎn);〔3〕事務(wù)管理特性,強(qiáng)制保持事務(wù)的原子性和一致性。事務(wù)啟動(dòng)之后,就必須成功完成,否那么數(shù)據(jù)庫引擎實(shí)例將撤消該事務(wù)啟動(dòng)之后對(duì)數(shù)據(jù)所做的所有修改。12.1.4控制事務(wù)應(yīng)用程序主要通過指定事務(wù)啟動(dòng)和結(jié)束的時(shí)間來控制事務(wù)。可以使用Transact-SQL語句或數(shù)據(jù)庫應(yīng)用程序編程接口(API)函數(shù)來指定這些時(shí)間。系統(tǒng)還必須能夠正確處理那些在事務(wù)完成之前便終止事務(wù)的錯(cuò)誤。默認(rèn)情況下,事務(wù)按連接級(jí)別進(jìn)行管理。在一個(gè)連接上啟動(dòng)一個(gè)事務(wù)后,該事務(wù)結(jié)束之前,在該連接上執(zhí)行的所有Transact-SQL語句都是該事務(wù)的一局部。但是,在多個(gè)活動(dòng)的結(jié)果集(MultipleActiveResultSets,MARS)會(huì)話中,Transact-SQL顯式或隱式事務(wù)將變成批范圍的事務(wù),這種事務(wù)按批處理級(jí)別進(jìn)行管理。當(dāng)批處理完成時(shí),如果批范圍的事務(wù)還沒有提交或回滾,SQLServer將自動(dòng)回滾該事務(wù)。MARS使數(shù)據(jù)庫應(yīng)用程序允許應(yīng)用程序在單一連接中交錯(cuò)執(zhí)行多個(gè)請(qǐng)求,能在單個(gè)連接上保持多個(gè)活動(dòng)語句,具體而言,每個(gè)連接可以具有多個(gè)活動(dòng)的默認(rèn)結(jié)果集。應(yīng)用程序可以同時(shí)翻開多個(gè)默認(rèn)結(jié)果集,并且交錯(cuò)讀取它們。應(yīng)用程序可以在默認(rèn)結(jié)果集翻開的同時(shí)執(zhí)行如INSERT、UPDATE、DELETE和存儲(chǔ)過程調(diào)用等語句?!?〕啟動(dòng)事務(wù)使用API函數(shù)和Transact-SQL語句,可以在SQLServer數(shù)據(jù)庫引擎實(shí)例中將事務(wù)作為顯式、自動(dòng)提交或隱式事務(wù)來啟動(dòng)。在MARS會(huì)話中,Transact-SQL顯式和隱式事務(wù)將變成批范圍的事務(wù)。根據(jù)運(yùn)行模式,SQLServer2008將事務(wù)分為4種類型:自動(dòng)提交事務(wù)、顯示事務(wù)、隱式事務(wù)和批處理級(jí)事務(wù)。顯式事務(wù)通過API函數(shù)或通過發(fā)出Transact-SQLBEGINTRANSACTION語句來顯式啟動(dòng)事務(wù)。自動(dòng)提交事務(wù)數(shù)據(jù)庫引擎的默認(rèn)模式。每個(gè)單獨(dú)的Transact-SQL語句都在其完成后提交。不必指定任何語句來控制事務(wù)。隱式事務(wù)通過API函數(shù)或Transact-SQLSETIMPLICIT_TRANSACTIONSON語句,將隱性事務(wù)模式設(shè)置為翻開。下一個(gè)語句自動(dòng)啟動(dòng)一個(gè)新事務(wù)。當(dāng)該事務(wù)完成時(shí),下一個(gè)Transact-SQL語句又將啟動(dòng)一個(gè)新事務(wù)。批范圍的事務(wù)只適用于多個(gè)活動(dòng)的結(jié)果集(MARS),在MARS會(huì)話中啟動(dòng)的Transact-SQL顯式或隱式事務(wù)將變成批范圍的事務(wù)。當(dāng)批處理完成時(shí),如果批范圍的事務(wù)還沒有提交或回滾,SQLServer將自動(dòng)回滾該事務(wù)。事務(wù)模式按連接級(jí)別進(jìn)行管理。一個(gè)連接的事務(wù)模式發(fā)生變化對(duì)任何其它連接的事務(wù)模式?jīng)]有影響?!?〕結(jié)束事務(wù)使用COMMIT或ROLLBACK語句,或者通過API函數(shù)來結(jié)束事務(wù)。COMMIT如果事務(wù)成功,那么提交。COMMIT語句保證事務(wù)的所有修改在數(shù)據(jù)庫中都永久有效。COMMIT語句還釋放事務(wù)使用的資源〔例如,鎖〕。ROLLBACK如果事務(wù)中出現(xiàn)錯(cuò)誤,或用戶決定取消事務(wù),那么回滾該事務(wù)。ROLLBACK語句通過將數(shù)據(jù)返回到它在事務(wù)開始時(shí)所處的狀態(tài),來取消事務(wù)中的所有修改。ROLLBACK還釋放事務(wù)占用的資源。注意,在為支持多個(gè)活動(dòng)的結(jié)果集(MARS)而建立的連接中,只要還有待執(zhí)行的請(qǐng)求,就無法提交通過API函數(shù)啟動(dòng)的顯式事務(wù)。如果在未完成的操作還在運(yùn)行時(shí)嘗試提交此類事務(wù),將導(dǎo)致出現(xiàn)錯(cuò)誤?!?〕指定事務(wù)邊界可以使用Transact-SQL語句或API函數(shù)和方法來確定數(shù)據(jù)庫引擎事務(wù)啟動(dòng)和結(jié)束的時(shí)間。方法一:使用“Transact-SQL語句”指定事務(wù)邊界可以使用BEGINTRANSACTION、COMMITTRANSACTION、COMMITWORK、ROLLBACKTRANSACTION、ROLLBACKWORK和SETIMPLICIT_TRANSACTIONS語句來描述事務(wù)。這些語句主要用于數(shù)據(jù)庫應(yīng)用程序和Transact-SQL腳本〔如使用osql命令提示實(shí)用工具運(yùn)行的腳本〕中。osql工具是一個(gè)MicrosoftWindows32命令提示符工具,可以使用它運(yùn)行Transact-SQL語句和腳本文件。方法二:使用“API函數(shù)和方法”指定事務(wù)邊界數(shù)據(jù)庫API〔如ODBC、OLEDB、ADO和.NETFrameworkSQLClient命名空間〕包含用于描述事務(wù)的函數(shù)或方法。這些是數(shù)據(jù)庫引擎應(yīng)用程序中用于控制事務(wù)的主要機(jī)制。每個(gè)事務(wù)都必須只由其中一種方法管理。在對(duì)同一事務(wù)使用兩種方法會(huì)導(dǎo)致出現(xiàn)不確定的結(jié)果。例如,不應(yīng)先使用ODBCAPI函數(shù)啟動(dòng)一個(gè)事務(wù),再使用Transact-SQLCOMMIT語句完成該事務(wù)。這樣將無法向SQLServerODBC驅(qū)動(dòng)程序通知已提交該事務(wù)。在這種情況下,應(yīng)使用ODBCSQLEndTran函數(shù)結(jié)束該事務(wù)。〔4〕事務(wù)處理過程中的錯(cuò)誤如果某個(gè)錯(cuò)誤使事務(wù)無法成功完成,SQLServer會(huì)自動(dòng)回滾該事務(wù),并釋放該事務(wù)占用的所有資源。如果客戶端與數(shù)據(jù)庫引擎實(shí)例的網(wǎng)絡(luò)連接中斷了,那么當(dāng)網(wǎng)絡(luò)向?qū)嵗ㄖ撝袛嗪?,該連接的所有未完成事務(wù)均會(huì)被回滾。如果客戶端應(yīng)用程序失敗或客戶端計(jì)算機(jī)崩潰或重新啟動(dòng),也會(huì)中斷連接,而且當(dāng)網(wǎng)絡(luò)向數(shù)據(jù)庫引擎實(shí)例通知該中斷后,該實(shí)例會(huì)回滾所有未完成的連接。如果客戶端從該應(yīng)用程序注銷,所有未完成的事務(wù)也會(huì)被回滾。如果批中出現(xiàn)運(yùn)行時(shí)語句錯(cuò)誤〔如違反約束〕,那么數(shù)據(jù)庫引擎中的默認(rèn)行為是只回滾產(chǎn)生該錯(cuò)誤的語句??梢允褂肧ETXACT_ABORT語句更改此行為。在執(zhí)行SETXACT_ABORTON語句后,任何運(yùn)行時(shí)語句錯(cuò)誤都將導(dǎo)致自動(dòng)回滾當(dāng)前事務(wù)。編譯錯(cuò)誤〔如語法錯(cuò)誤〕不受SETXACT_ABORT的影響。出現(xiàn)錯(cuò)誤時(shí),糾正操作〔COMMIT或ROLLBACK〕應(yīng)包括在應(yīng)用程序代碼中。一種處理錯(cuò)誤〔包括那些事務(wù)中的錯(cuò)誤〕的有效工具是Transact-SQLTRY...CATCH構(gòu)造。12.1.5顯式事務(wù)顯式事務(wù)就是可以顯式地在其中定義事務(wù)的開始和結(jié)束的事務(wù)。DB-Library應(yīng)用程序和Transact-SQL腳本使用BEGINTRANSACTION、COMMITTRANSACTION、COMMITWORK、ROLLBACKTRANSACTION或ROLLBACKWORKTransact-SQL語句定義顯式事務(wù)?!?〕BEGINTRANSACTION標(biāo)記顯式連接事務(wù)的起始點(diǎn)?!?〕COMMITTRANSACTION或COMMITWORK如果沒有遇到錯(cuò)誤,可使用該語句成功地結(jié)束事務(wù)。該事務(wù)中的所有數(shù)據(jù)修改在數(shù)據(jù)庫中都將永久有效。事務(wù)占用的資源將被釋放。〔3〕ROLLBACKTRANSACTION或ROLLBACKWORK用來去除遇到錯(cuò)誤的事務(wù)。該事務(wù)修改的所有數(shù)據(jù)都返回到事務(wù)開始時(shí)的狀態(tài)。事務(wù)占用的資源將被釋放。還可以在OLEDB中使用顯式事務(wù)。調(diào)用ITransactionLocal::StartTransaction方法可啟動(dòng)事務(wù)。如果將fRetainin設(shè)置為FALSE,通過調(diào)用ITransaction::Commit或ITransaction::Abort方法結(jié)束事務(wù)時(shí)不會(huì)自動(dòng)啟動(dòng)另一事務(wù)。在ADO中,對(duì)Connection對(duì)象使用BeginTrans方法可啟動(dòng)隱式事務(wù)。假設(shè)要結(jié)束該事務(wù),可調(diào)用該Connection對(duì)象的CommitTrans或RollbackTrans方法。在ADO.NETSqlClient托管提供程序中,對(duì)SqlConnection對(duì)象使用BeginTransaction方法可以啟動(dòng)一個(gè)顯式事務(wù)。假設(shè)要結(jié)束事務(wù),可以對(duì)SqlTransaction對(duì)象調(diào)用Commit()或Rollback()方法。ODBCAPI不支持顯式事務(wù),只支持自動(dòng)提交和隱式事務(wù)。顯式事務(wù)模式持續(xù)的時(shí)間只限于該事務(wù)的持續(xù)期。當(dāng)事務(wù)結(jié)束時(shí),連接將返回到啟動(dòng)顯式事務(wù)前所處的事務(wù)模式,或者是隱式模式,或者是自動(dòng)提交模式。注意,在多個(gè)活動(dòng)的結(jié)果集(MARS)會(huì)話中,通過Transact-SQLBEGINTRANSACTION語句啟動(dòng)的顯式事務(wù)將變成批范圍的事務(wù)。如果批范圍的事務(wù)在批處理完成時(shí)還沒有提交或回滾,SQLServer將自動(dòng)回滾該事務(wù)。12.1.5自動(dòng)提交事務(wù)自動(dòng)提交模式是SQLServer數(shù)據(jù)庫引擎的默認(rèn)事務(wù)管理模式。每個(gè)Transact-SQL語句在完成時(shí),都被提交或回滾。如果一個(gè)語句成功地完成,那么提交該語句;如果遇到錯(cuò)誤,那么回滾該語句。只要沒有顯式事務(wù)或隱性事務(wù)覆蓋自動(dòng)提交模式,與數(shù)據(jù)庫引擎實(shí)例的連接就以此默認(rèn)模式操作。自動(dòng)提交模式也是ADO、OLEDB、ODBC和DB庫的默認(rèn)模式。在BEGINTRANSACTION語句啟動(dòng)顯式事務(wù)或隱性事務(wù)設(shè)置為開啟之前,與數(shù)據(jù)庫引擎實(shí)例的連接一直以自動(dòng)提交模式操作。當(dāng)提交或回滾顯式事務(wù)或關(guān)閉隱性事務(wù)模式時(shí),連接將返回到自動(dòng)提交模式。如果設(shè)置為ON,SETIMPLICIT_TRANSACTIONS會(huì)將連接設(shè)置為隱式事務(wù)模式。如果設(shè)置為OFF,那么使連接恢復(fù)為自動(dòng)提交事務(wù)模式。12.1.6隱式事務(wù)當(dāng)連接以隱性事務(wù)模式進(jìn)行操作時(shí),SQLServer數(shù)據(jù)庫引擎實(shí)例將在提交或回滾當(dāng)前事務(wù)后自動(dòng)啟動(dòng)新事務(wù)。無須描述事務(wù)的開始,只需提交或回滾每個(gè)事務(wù)。隱性事務(wù)模式生成連續(xù)的事務(wù)鏈。為連接將隱性事務(wù)模式設(shè)置為翻開之后,當(dāng)數(shù)據(jù)庫引擎實(shí)例首次執(zhí)行ALTERTABLE、INSERT、CREATE、OPEN、DELETE、REVOKE、DROP、SELECT、FETCH、TRUNCATETABLE、GRANT、UPDATE這些語句的任何一個(gè)時(shí),都會(huì)自動(dòng)啟動(dòng)一個(gè)事務(wù)。在發(fā)出COMMIT或ROLLBACK語句之前,該事務(wù)將一直保持有效。在第一個(gè)事務(wù)被提交或回滾之后,下次當(dāng)連接執(zhí)行以上任何語句時(shí),數(shù)據(jù)庫引擎實(shí)例都將自動(dòng)啟動(dòng)一個(gè)新事務(wù)。該實(shí)例將不斷地生成隱性事務(wù)鏈,直到隱性事務(wù)模式關(guān)閉為止。隱性事務(wù)模式既可以使用Transact-SQLSET語句來設(shè)置,也可以通過數(shù)據(jù)庫API函數(shù)和方法來設(shè)置。注意,在多個(gè)活動(dòng)的結(jié)果集(MARS)會(huì)話中,Transact-SQL隱式事務(wù)將變成批范圍的事務(wù)。如果批范圍的事務(wù)在批處理完成時(shí)還沒有提交或回滾,SQLServer將自動(dòng)回滾該事務(wù)。SETIMPLICIT_TRANSACTIONS:將連接設(shè)置為隱式事務(wù)模式。語法:SETIMPLICIT_TRANSACTIONS{ON|OFF}說明:如果設(shè)置為ON,SETIMPLICIT_TRANSACTIONS將連接設(shè)置為隱式事務(wù)模式。如果設(shè)置為OFF,那么使連接恢復(fù)為自動(dòng)提交事務(wù)模式。如果連接處于隱式事務(wù)模式,并且當(dāng)前不在事務(wù)中,那么執(zhí)行表12-1任一語句如都可啟動(dòng)事務(wù)。表12-1語句關(guān)鍵字語句關(guān)鍵字ALTERTABLEFETCHREVOKECREATEGRANTSELECTDELETEINSERTTRUNCATETABLEDROPOPENUPDATE如果連接已經(jīng)在翻開的事務(wù)中,那么上述語句不會(huì)啟動(dòng)新事務(wù)。對(duì)于因?yàn)榇嗽O(shè)置為ON而自動(dòng)翻開的事務(wù),用戶必須在該事務(wù)結(jié)束時(shí)將其顯式提交或回滾。否那么,當(dāng)用戶斷開連接時(shí),事務(wù)及其包含的所有數(shù)據(jù)更改將被回滾。事務(wù)提交后,執(zhí)行上述任一語句即可啟動(dòng)一個(gè)新事務(wù)。隱式事務(wù)模式將始終生效,直到連接執(zhí)行SETIMPLICIT_TRANSACTIONSOFF語句使連接恢復(fù)為自動(dòng)提交模式。在自動(dòng)提交模式下,所有單個(gè)語句在成功完成時(shí)將被提交。進(jìn)行連接時(shí),SQLServerNativeClientOLEDBProviderforSQLServer和SQLServerNativeClientODBC驅(qū)動(dòng)程序會(huì)自動(dòng)將IMPLICIT_TRANSACTIONS設(shè)置為OFF。對(duì)于與SQLClient托管提供程序的連接以及通過HTTP端點(diǎn)接收的SOAP請(qǐng)求,SETIMPLICIT_TRANSACTIONS默認(rèn)為OFF。如果SETANSI_DEFAULTS為ON,那么SETIMPLICIT_TRANSACTIONS也為ON。SETIMPLICIT_TRANSACTIONS的設(shè)置是在執(zhí)行或運(yùn)行時(shí)設(shè)置的,而不是在分析時(shí)設(shè)置的。12.1.7分布式事務(wù)〔數(shù)據(jù)庫引擎〕分布式事務(wù)跨越兩個(gè)或多個(gè)稱為資源管理器的效勞器。稱為事務(wù)管理器的效勞器組件必須在資源管理器之間協(xié)調(diào)事務(wù)管理。如果分布式事務(wù)由Microsoft分布式事務(wù)處理協(xié)調(diào)器(MSDTC)之類的事務(wù)管理器或其它支持OpenGroupXA分布式事務(wù)處理標(biāo)準(zhǔn)的事務(wù)管理器來協(xié)調(diào),那么在這樣的分布式事務(wù)中,每個(gè)SQLServer數(shù)據(jù)庫引擎實(shí)例都可以作為資源管理器來運(yùn)行??缭絻蓚€(gè)或多個(gè)數(shù)據(jù)庫的單個(gè)數(shù)據(jù)庫引擎實(shí)例中的事務(wù)實(shí)際上是分布式事務(wù)。該實(shí)例對(duì)分布式事務(wù)進(jìn)行內(nèi)部管理;對(duì)于用戶而言,其操作就像本地事務(wù)一樣。對(duì)于應(yīng)用程序而言,管理分布式事務(wù)很像管理本地事務(wù)。當(dāng)事務(wù)結(jié)束時(shí),應(yīng)用程序會(huì)請(qǐng)求提交或回滾事務(wù)。不同的是,分布式提交必須由事務(wù)管理器管理,以盡量防止出現(xiàn)因網(wǎng)絡(luò)故障而導(dǎo)致事務(wù)由某些資源管理器成功提交,但由另一些資源管理器回滾的情況。通過分兩個(gè)階段〔準(zhǔn)備階段和提交階段〕管理提交進(jìn)程可防止這種情況,這稱為兩階段提交(Two-PhaseCommit,2PC)。〔1〕準(zhǔn)備階段當(dāng)事務(wù)管理器收到提交請(qǐng)求時(shí),它會(huì)向該事務(wù)涉及的所有資源管理器發(fā)送準(zhǔn)備命令。然后,每個(gè)資源管理器將盡力使該事務(wù)持久,并且所有保存該事務(wù)日志映像的緩沖區(qū)將被刷新到磁盤中。當(dāng)每個(gè)資源管理器完成準(zhǔn)備階段時(shí),它會(huì)向事務(wù)管理器返回準(zhǔn)備成功或準(zhǔn)備失敗的消息?!?〕提交階段如果事務(wù)管理器從所有資源管理器收到準(zhǔn)備成功的消息,它將向每個(gè)資源管理器發(fā)送一個(gè)提交命令。然后,資源管理器就可以完成提交。如果所有資源管理器都報(bào)告提交成功,那么事務(wù)管理器就會(huì)向應(yīng)用程序發(fā)送一個(gè)成功通知。如果任一資源管理器報(bào)告準(zhǔn)備失敗,那么事務(wù)管理器將向每個(gè)資源管理器發(fā)送一個(gè)回滾命令,并向應(yīng)用程序說明提交失敗。數(shù)據(jù)庫引擎應(yīng)用程序可以通過Transact-SQL或數(shù)據(jù)庫API來管理分布式事務(wù)。12.1.8Transact-SQL事務(wù)處理語句SQLServer提供以下事務(wù)語句。〔1〕BEGINTRANSACTIONBEGINTRANSACTION:標(biāo)記一個(gè)顯式本地事務(wù)的起始點(diǎn)。BEGINTRANSACTION使@@TRANCOUNT按1遞增。〔2〕BEGINDISTRIBUTEDTRANSACTION:指定一個(gè)由Microsoft分布式事務(wù)處理協(xié)調(diào)器(MSDTC)管理的Transact-SQL分布式事務(wù)的起始?!?〕COMMITTRANSACTION:標(biāo)志一個(gè)成功的隱性事務(wù)或顯式事務(wù)的結(jié)束。如果@@TRANCOUNT為1,COMMITTRANSACTION使得自從事務(wù)開始以來所執(zhí)行的所有數(shù)據(jù)修改成為數(shù)據(jù)庫的永久局部,釋放事務(wù)所占用的資源,并將@@TRANCOUNT減少到0。如果@@TRANCOUNT大于1,那么COMMITTRANSACTION使@@TRANCOUNT按1遞減并且事務(wù)將保持活動(dòng)狀態(tài)?!?〕COMMITWORK:標(biāo)志事務(wù)的結(jié)束。此語句的功能與COMMITTRANSACTION相同,但COMMITTRANSACTION接受用戶定義的事務(wù)名稱?!?〕ROLLBACKTRANSACTION:將顯式事務(wù)或隱性事務(wù)回滾到事務(wù)的起點(diǎn)或事務(wù)內(nèi)的某個(gè)保存點(diǎn)?!?〕ROLLBACKWORK:將用戶定義的事務(wù)回滾到事務(wù)的起點(diǎn)。此語句的功能與ROLLBACKTRANSACTION相同,但ROLLBACKTRANSACTION接受用戶定義的事務(wù)名稱?!?〕SAVETRANSACTION:在事務(wù)內(nèi)設(shè)置保存點(diǎn)。系統(tǒng)內(nèi)置函數(shù)@@TRANCOUNT:返回在當(dāng)前連接上已發(fā)生的BEGINTRANSACTION語句的數(shù)目。@@TRANCOUNT有時(shí)也稱為全局變量。BEGINTRANSACTION語句將@@TRANCOUNT增加1。ROLLBACKTRANSACTION將@@TRANCOUNT遞減到0,但ROLLBACKTRANSACTIONsavepoint_name除外,它不影響@@TRANCOUNT。COMMITTRANSACTION或COMMITWORK將@@TRANCOUNT遞減1?!纠?2-1】事務(wù)的顯式開始和顯式回滾。在SQLServerManagementStudio的【標(biāo)準(zhǔn)】工具欄上,單擊【新建查詢】按鈕。此時(shí)將使用當(dāng)前連接翻開一個(gè)查詢編輯器窗口。輸入如下代碼,單擊【SQL編輯器】工具欄上的【執(zhí)行】按鈕,在【結(jié)果】/【消息】窗格中查看結(jié)果。USETempDB;/*使用TempDB作為當(dāng)前數(shù)據(jù)庫*/GO--TempDB數(shù)據(jù)庫中假設(shè)存在用戶創(chuàng)立的表TestTable,那么刪除之。IFOBJECT_ID(N'TempDB..TestTable',N'U')ISNOTNULL DROPTABLETestTable;GOCREATETABLETestTable([ID]int,[name]nchar(10))GODECLARE@TransactionNamevarchar(20);/*聲明局部變量*/set@TransactionName='Transaction1';/*局部變量賦初值*/PRINT@@TRANCOUNT/*向客戶端返回當(dāng)前連接上已發(fā)生的BEGINTRANSACTION語句數(shù)*/BEGINTRAN@TransactionName/*顯式開始事務(wù)*/ PRINT@@TRANCOUNT INSERTINTOTestTableVALUES(1,'David')/*插入記錄到表*/ INSERTINTOTestTableVALUES(2,'John')/*插入記錄到表*/ ROLLBACKTRAN@TransactionName/*顯式回滾事務(wù),取消插入操作,將表中數(shù)據(jù)恢復(fù)到初始狀態(tài)*/PRINT@@TRANCOUNTBEGINTRAN@TransactionName PRINT@@TRANCOUNT INSERTINTOTestTableVALUES(3,'Jone') INSERTINTOTestTableVALUES(4,'Rose') If@@error>0--如果系統(tǒng)出現(xiàn)意外 ROLLBACKTRAN@TransactionName--那么進(jìn)行回滾操作 Else COMMITTRAN@TransactionName/*顯式提交事務(wù)*/PRINT@@TRANCOUNTSELECT*FROMTestTable/*查詢表的所有記錄*/--Results--IDname--3Jone--4RoseDROPTABLETestTable/*刪除表*/【例12-2】為教師表插入一名教師的信息,如果正常運(yùn)行那么插入數(shù)據(jù)表中,反之那么回滾。此題注意學(xué)習(xí)SAVETRANSACTION語句。USETempDB;/*使用TempDB作為當(dāng)前數(shù)據(jù)庫*/GO--TempDB數(shù)據(jù)庫中假設(shè)存在用戶創(chuàng)立的表Teacher,那么刪除之。IFOBJECT_ID(N'TempDB..Teacher',N'U')ISNOTNULL DROPTABLETeacher;GOCREATETABLETeacher([ID]int,[name]nchar(10),[birthday]datetime,depatrmentnchar(4),salaryintnull)GOBegintransactionInsertintoteachervalues('101','王偉',1990-03-02,'計(jì)算機(jī)系',1000)Insertintoteachervalues('102','李紅',1900-08-08,'計(jì)算機(jī)系',1000)select*fromTeacher;updateteachersetsalary=salary+100--給每名教師的薪水加元Savetransactionsavepoint1Insertintoteachervalues('840','李強(qiáng)',1975-03-02,'計(jì)算機(jī)系',null)If@@error>0rollbacktransactionsavepoint1If@@error>0rollbacktransactionElsecommittransactionselect*fromTeacher;注意:savetransaction命令后面有一個(gè)名字,這就是在事務(wù)內(nèi)設(shè)置的保存點(diǎn)的名字,這樣在第一次回滾時(shí),就可以回滾到這個(gè)存儲(chǔ)點(diǎn),就是savepoint1,而不是回滾整個(gè)的事務(wù)。Insertintoteacher會(huì)被取消,但是事務(wù)本身仍然將繼續(xù)。也就是插入的教師信息將從事務(wù)中除去,數(shù)據(jù)表撤銷該教師信息的插入,但是給每名教師的薪水加100元的操作正常的被保存到數(shù)據(jù)庫之中;到了后一個(gè)回滾,由于沒有給出回滾到的保存點(diǎn)名字,rollbacktransaction將回滾到begintransaction前的狀態(tài),即修改和插入操作都被撤銷,就像沒有發(fā)生任何事情一樣。4.如何編寫有效的事務(wù)事務(wù)的編寫是T-SQL編程過程中非常重要的操作,因此數(shù)據(jù)庫專家根據(jù)事務(wù)編程的特點(diǎn),總結(jié)并歸納出以下幾個(gè)要點(diǎn),以期到達(dá)編寫有效事務(wù)的目的:〔1〕不要在事務(wù)處理期間要求用戶輸入數(shù)據(jù)。〔2〕在事務(wù)啟動(dòng)之前,你必須要獲得所有需要的用戶輸入?!?〕在瀏覽數(shù)據(jù)的時(shí)候,盡量不要翻開事務(wù)。〔4〕在所有的數(shù)據(jù)檢索分析完畢之前,不應(yīng)該啟動(dòng)事務(wù)?!?〕事務(wù)的代碼編寫盡可能簡短?!?〕在知道了必須要進(jìn)行的修改之后,啟動(dòng)事務(wù),執(zhí)行修改語句,然后立即提交或者回滾。〔7〕在事務(wù)中盡量使訪問的數(shù)據(jù)量最小化。〔8〕盡量減少鎖定數(shù)據(jù)表的行數(shù),從而減少事務(wù)之間的競爭。12.1.9事務(wù)的分類根據(jù)系統(tǒng)的設(shè)置分類根據(jù)系統(tǒng)的設(shè)置來分類,SQLServer2008將事務(wù)分為兩種類型:系統(tǒng)提供的事務(wù)和用戶定義的事務(wù),分別簡稱為系統(tǒng)事務(wù)和用戶定義事務(wù)。〔1〕系統(tǒng)事務(wù)系統(tǒng)提供的事務(wù)是指在執(zhí)行某些語句時(shí),一條語句就是一個(gè)事務(wù)。但是要明確,一條語句的對(duì)象既可能是表中的一行數(shù)據(jù),也可能是表中的多行數(shù)據(jù),甚至是表中的全部數(shù)據(jù)。因此,只有一條語句構(gòu)成的事務(wù)也可能包含了多行數(shù)據(jù)的處理。系統(tǒng)提供的事務(wù)語句如下:ALTERTABLE、CREATE、DELETE、DROP、FETCH、GRANT、INSERT、OPEN、REBOKE、SELECT、UPDATE、TRUNCATETABLE這些語句本身就構(gòu)成了一個(gè)事務(wù)?!纠?2-3】使用CREATETABLE創(chuàng)立一個(gè)表。CREATETABLEstudent(idCHAR(10),nameCHAR(6),sexCHAR(2))說明:這條語句本身就構(gòu)成了一個(gè)事務(wù)。這條語句由于沒有使用條件限制,那么這條語句就是創(chuàng)立包含3個(gè)列的表。要么創(chuàng)立全部成功,要么全部失敗?!?〕用戶定義事務(wù)在實(shí)際應(yīng)用中,大多數(shù)的事務(wù)處理采用了用戶定義的事務(wù)來處理。在開發(fā)應(yīng)用程序時(shí),可以使用BEGINTRANSACTION語句來定義明確的用戶定義的事務(wù)。在使用用戶定義的事務(wù)時(shí),一定要注意事務(wù)必須有明確的結(jié)束語句來結(jié)束。如果不使用明確的結(jié)束語句來結(jié)束,那么系統(tǒng)可能把從事務(wù)開始到用戶關(guān)閉連接之間的全部操作都作為一個(gè)事務(wù)來對(duì)待。事務(wù)的明確結(jié)束可以使用兩個(gè)語句中的一個(gè):COMMIT語句和ROLLBACK語句。COMMIT語句是提交語句,將全部完成的語句明確地提交到數(shù)據(jù)庫中。ROLLBACK語句是取消語句,該語句將事務(wù)的操作全部取消,即表示事務(wù)操作失敗。還有一種特殊的用戶定義的事務(wù),這就是分布式事務(wù)。例3的事務(wù)是在一個(gè)效勞器上的操作,其保證的數(shù)據(jù)完整性和一致性是指一個(gè)效勞器上的完整性和一致性。但是,如果一個(gè)比較復(fù)雜的環(huán)境,可能有多臺(tái)效勞器,那么要保證在多臺(tái)效勞器環(huán)境中事務(wù)的完整性和一致性,就必須定義一個(gè)分布式事務(wù)。在這個(gè)分布式事務(wù)中,所有的操作都可以涉及對(duì)多個(gè)效勞器的操作,當(dāng)這些操作都成功時(shí),那么所有這些操作都提交到相應(yīng)效勞器的數(shù)據(jù)庫中,如果這些操作中有一個(gè)操作失敗,那么這個(gè)分布式事務(wù)中的全部操作都將被取消。12.2數(shù)據(jù)庫并發(fā)控制數(shù)據(jù)庫是一個(gè)多用戶使用的共享資源。多個(gè)用戶或應(yīng)用程序可能同時(shí)對(duì)數(shù)據(jù)庫的同一數(shù)據(jù)對(duì)象進(jìn)行讀寫操作,這種現(xiàn)象稱為對(duì)數(shù)據(jù)庫的并發(fā)操作。當(dāng)多個(gè)用戶事務(wù)并發(fā)地存取某數(shù)據(jù)庫的同一數(shù)據(jù)時(shí),假設(shè)對(duì)并發(fā)操作不加控制就可能會(huì)讀取和存儲(chǔ)不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的一致性。12.1并發(fā)控制概述1、不同的多事務(wù)執(zhí)行方式多事務(wù)的執(zhí)行方式分為串行執(zhí)行方式、交叉并發(fā)方式、同時(shí)并發(fā)方式。如圖12-1所示。(1)事務(wù)串行執(zhí)行特點(diǎn):每個(gè)時(shí)刻只有一個(gè)事務(wù)運(yùn)行,其它事務(wù)必須等到這個(gè)事務(wù)結(jié)束以前方能運(yùn)行。優(yōu)點(diǎn):不能充分利用系統(tǒng)資源,不能發(fā)揮數(shù)據(jù)庫共享資源的特點(diǎn)。(2)交叉并發(fā)方式〔InterleavedConcurrency〕特點(diǎn):在單處理機(jī)系統(tǒng)中,事務(wù)的并行執(zhí)行是這些并行事務(wù)的并行操作輪流交叉運(yùn)行。優(yōu)點(diǎn):單處理機(jī)系統(tǒng)中的并行事務(wù)并沒有真正地并行運(yùn)行,但能夠減少處理機(jī)的空閑時(shí)間,提高系統(tǒng)的效率。圖12-1事務(wù)的串行執(zhí)行和交叉并行執(zhí)行示意圖(3)同時(shí)并發(fā)方式〔simultaneousconcurrency〕多處理機(jī)系統(tǒng)中,每個(gè)處理機(jī)可以運(yùn)行一個(gè)事務(wù),多個(gè)處理機(jī)可以同時(shí)運(yùn)行多個(gè)事務(wù),實(shí)現(xiàn)多個(gè)事務(wù)真正的并行運(yùn)行;最理想的并發(fā)方式,但受制于硬件環(huán)境。12.2并發(fā)操作帶來的數(shù)據(jù)不一致性問題修改數(shù)據(jù)的用戶會(huì)影響同時(shí)讀取或修改相同數(shù)據(jù)的其他用戶。即這些用戶可以并發(fā)訪問數(shù)據(jù)。這里以庫存管理為例,說明如果數(shù)據(jù)存儲(chǔ)系統(tǒng)沒有并發(fā)控制,對(duì)并發(fā)操作不加以限制,會(huì)產(chǎn)生數(shù)據(jù)不一致性問題,這種問題共有3類:包括喪失更新、不可重復(fù)讀、讀“臟”數(shù)據(jù)。1.喪失更新當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí),會(huì)發(fā)生喪失更新問題。每個(gè)事務(wù)都不知道其他事務(wù)的存在。最后的更新將覆蓋由其他事務(wù)所做的更新,這將導(dǎo)致數(shù)據(jù)喪失。假設(shè)某產(chǎn)品庫存量為50,現(xiàn)在購入該產(chǎn)品100個(gè),執(zhí)行入庫操作,庫存量加100;用掉40個(gè),執(zhí)行出庫操作,庫存量減40。分別用T1和T2表示入庫和出庫操作任務(wù)。例如,同時(shí)發(fā)生入庫〔T1〕和出庫〔T2〕操作,這就形成并發(fā)操作。T1讀取庫存后,T2也讀取了同一個(gè)庫存;T1修改庫存,回寫更新后的值;T2修改庫存,也回寫更新后的值。此時(shí)庫存為T2回寫的值,T1對(duì)庫存的更新喪失。如表12-2所示T1和T2的并發(fā)操作執(zhí)行順序,發(fā)生了“喪失更新”錯(cuò)誤。表12-2發(fā)生喪失更新的過程順序任務(wù)操作庫存量1T1讀庫存量502T2讀庫存量503T1庫存量=50+100
4T2庫存量=50-40
5T1寫庫存量1506T2寫庫存量102.讀“臟數(shù)據(jù)”當(dāng)?shù)诙€(gè)事務(wù)選擇其他事務(wù)正在更新的行時(shí),會(huì)發(fā)生未提交的依賴關(guān)系問題。第二個(gè)事務(wù)正在讀取的數(shù)據(jù)還沒有被提交并且可能由更新此行的事務(wù)所更改。當(dāng)T1和T2并發(fā)執(zhí)行時(shí),在T1對(duì)數(shù)據(jù)庫更新的結(jié)果沒有提交之前,T2使用了T1的結(jié)果,而在T2操作之后T1又回滾,這時(shí)引起的錯(cuò)誤是T2讀取了T1的“臟數(shù)據(jù)”。表12-3所示的執(zhí)行過程就產(chǎn)生了這種錯(cuò)誤。表12-3T2使用T1的“臟數(shù)據(jù)”的過程順序任務(wù)操作庫存量1T1讀庫存量502T1庫存量=50+100
3T1寫庫存量1504T2讀庫存量1505T2庫存量=150-40
6T1ROLLBACK507T2寫庫存量1103.不可重復(fù)讀當(dāng)?shù)诙€(gè)事務(wù)屢次訪問同一行而且每次讀取不同的數(shù)據(jù)時(shí),會(huì)發(fā)生不一致的分析問題。不一致的分析與未提交的依賴關(guān)系類似,因?yàn)槠渌聞?wù)也是正在更改第二個(gè)事務(wù)正在讀取的數(shù)據(jù)。但是,在不一致的分析中,第二個(gè)事務(wù)讀取的數(shù)據(jù)是由已進(jìn)行了更改的事務(wù)提交的。此外,不一致的分析涉及屢次〔兩次或更多〕讀取同一行,而且每次信息都被其他事務(wù)更改,因此我們稱之為“不可重復(fù)讀”。當(dāng)T1讀取數(shù)據(jù)A后,T2執(zhí)行了對(duì)A的更新,當(dāng)T1再次讀取數(shù)據(jù)A〔希望與第一次是相同的值〕時(shí),得到的數(shù)據(jù)與前一次不同,這時(shí)引起的錯(cuò)誤稱為“不可重復(fù)讀”。表12-4所示的并發(fā)操作執(zhí)行過程,發(fā)生了“不可重復(fù)讀”錯(cuò)誤。并發(fā)操作之所以產(chǎn)生錯(cuò)誤,是因?yàn)槿蝿?wù)執(zhí)行期間相互干擾造成的。當(dāng)將任務(wù)定義成事務(wù),事務(wù)具有的特性〔特別是隔離性〕得以保證時(shí),就會(huì)防止上述錯(cuò)誤的發(fā)生。但是,如果只允許事務(wù)串行操作會(huì)降低系統(tǒng)的效率。所以,多數(shù)DBMS采用事務(wù)機(jī)制和封鎖機(jī)制進(jìn)行并發(fā)控制,既保證了數(shù)據(jù)的一致性,又保障了系統(tǒng)效率。表12-4T1對(duì)數(shù)據(jù)A“不可重復(fù)讀”的過程順序任務(wù)操作庫存量A入庫量B1T1讀A=50501002T1讀B=100
3T1求和=50+100
4T2讀B=10050
5T2B←B×4
6T2回寫B(tài)=400504007T1讀A=5050
8T1讀B=400
9T1和=450(驗(yàn)算不對(duì))
有三類不可重復(fù)讀:事務(wù)1讀取某一數(shù)據(jù)后:〔1〕事務(wù)2對(duì)其做了修改,當(dāng)事務(wù)1再次讀該數(shù)據(jù)時(shí),得到與前一次不同的值?!?〕事務(wù)2刪除了其中局部記錄,當(dāng)事務(wù)1再次讀取數(shù)據(jù)時(shí),發(fā)現(xiàn)某些記錄神密地消失了?!?〕事務(wù)2插入了一些記錄,當(dāng)事務(wù)1再次按相同條件讀取數(shù)據(jù)時(shí),發(fā)現(xiàn)多了一些記錄。后兩種不可重復(fù)讀有時(shí)也稱為幻影現(xiàn)象〔phantomrow〕或幻讀。分析以上三種錯(cuò)誤的原因,不難看出,上述三個(gè)操作序列違背了事務(wù)的四個(gè)特性。在產(chǎn)生并發(fā)操作時(shí)如何確保事務(wù)的特性不被破壞,防止上述錯(cuò)誤的發(fā)生?這就是并發(fā)控制要解決的問題。12.3封鎖機(jī)制12.3.1封鎖及鎖的類型封鎖機(jī)制是并發(fā)控制的主要手段。封鎖是使事務(wù)對(duì)它要操作的數(shù)據(jù)有一定的控制能力。封鎖具有3個(gè)環(huán)節(jié):第一個(gè)環(huán)節(jié)是申請(qǐng)加鎖,即事務(wù)在操作前要對(duì)它欲使用的數(shù)據(jù)提出加鎖請(qǐng)求;第二個(gè)環(huán)節(jié)是獲得鎖,即當(dāng)條件成熟時(shí),系統(tǒng)允許事務(wù)對(duì)數(shù)據(jù)加鎖,從而事務(wù)獲得數(shù)據(jù)的控制權(quán);第三個(gè)環(huán)節(jié)是釋放鎖,即完成操作后事務(wù)放棄數(shù)據(jù)的控制權(quán)。為了到達(dá)封鎖的目的,在使用時(shí)事務(wù)應(yīng)選擇適宜的鎖,并要遵從一定的封鎖協(xié)議。根本的封鎖類型有兩種:排它鎖(ExclusiveLocks,簡稱X鎖)和共享鎖(ShareLocks,簡稱S鎖)。(1)排它鎖排它鎖也稱為獨(dú)占鎖或?qū)戞i。一旦事務(wù)T對(duì)數(shù)據(jù)對(duì)象A加上排它鎖(X鎖),那么只允許T讀取和修改A,其它任何事務(wù)既不能讀取和修改A,也不能再對(duì)A加任何類型的鎖,直到T釋放A上的鎖為止。(2)共享鎖共享鎖又稱讀鎖。如果事務(wù)T對(duì)數(shù)據(jù)對(duì)象A加上共享鎖(S鎖),其它事務(wù)對(duì)A只能再加S鎖,不能加X鎖,直到事務(wù)T釋放A上的S鎖為止。12.3.2封鎖協(xié)議簡單地對(duì)數(shù)據(jù)加X鎖和S鎖并不能保證數(shù)據(jù)庫的一致性。在對(duì)數(shù)據(jù)對(duì)象加鎖時(shí),還需要約定一些規(guī)那么。例如,何時(shí)申請(qǐng)X鎖或S鎖、持鎖時(shí)間、何時(shí)釋放等。這些規(guī)那么稱為封鎖協(xié)議(LockingProtocol)。對(duì)封鎖方式規(guī)定不同的規(guī)那么,就形成了各種不同的封鎖協(xié)議。封鎖協(xié)議分三級(jí),各級(jí)封鎖協(xié)議對(duì)并發(fā)操作帶來的喪失修改、不可重復(fù)讀取和讀“臟”數(shù)據(jù)等不一致問題,可以在不同程度上予以解決。(1)一級(jí)封鎖協(xié)議一級(jí)封鎖協(xié)議是:事務(wù)T在修改數(shù)據(jù)之前必須先對(duì)其加X鎖,直到事務(wù)結(jié)束才釋放。根據(jù)該協(xié)議要求,將表12-1種的任務(wù)T1、T2作為事務(wù),用A表示庫存,重新執(zhí)行各操作的過程見表過程見表12-5。表12-5遵循一級(jí)封鎖協(xié)議的事務(wù)執(zhí)行過程順序T1T2庫存A的值1XlockA獲得
502讀A=50XlockA等待503A←A+100寫回A=150CommitUnlockA等待等待等待
1504
獲得XlockA讀A=150A←A-40回寫A=110CommitUlockA110可見,一級(jí)封鎖協(xié)議可有效地防止“喪失更新”,并能夠保證事務(wù)T的可恢復(fù)性。但是,由于一級(jí)封鎖沒有要求對(duì)讀數(shù)據(jù)進(jìn)行加鎖,所以不能保證可重復(fù)讀和不讀“臟”數(shù)據(jù)。表12-6所示的操作過程遵從一級(jí)封鎖協(xié)議,但仍然發(fā)生了讀“臟”數(shù)據(jù)錯(cuò)誤。讀者可以用類似的操作實(shí)例,便會(huì)發(fā)現(xiàn)一級(jí)封鎖協(xié)議也不能防止不可重復(fù)讀的錯(cuò)誤。表12-6遵從一級(jí)封鎖協(xié)議發(fā)生的讀“臟”數(shù)據(jù)過程順序T1T2庫存A的值1XlockA獲得讀A=50A←A+100寫回A=150UlockA
501502
讀A=1501503ROLLBACK
50(2)二級(jí)封鎖協(xié)議二級(jí)封鎖協(xié)議是:事務(wù)T對(duì)要修改數(shù)據(jù)必須先加X鎖,直到事務(wù)結(jié)束才釋放X鎖;對(duì)要讀取的數(shù)據(jù)必須先加S鎖,讀完后即可釋放S鎖。二級(jí)封鎖協(xié)議不但能夠防止喪失修改,還可進(jìn)一步防止讀“臟”數(shù)據(jù)。但是由于二級(jí)封鎖協(xié)議對(duì)數(shù)據(jù)讀完后即可釋放S鎖,所以不能防止“不可重復(fù)讀”錯(cuò)誤。例如,表12-7所示的并發(fā)操作執(zhí)行過程,遵從二級(jí)封鎖協(xié)議,但發(fā)生了“不可重復(fù)讀”錯(cuò)誤。表12-7遵從二級(jí)封鎖協(xié)議發(fā)生的“不可重復(fù)讀”的過程順序T1T2A的值B的值1SlockA,B獲得讀A=50讀B=100UlockA,BXlockB等待等待等待獲得50150100
2求和=150SlockA得到SlockB等待等待獲得讀B=100B←B×4回寫B(tài)=400CommitUlockB504003讀A=50讀B=400和=450(驗(yàn)算錯(cuò)誤)
50400(3)三級(jí)封鎖協(xié)議三級(jí)封鎖協(xié)議是事務(wù)T在讀取數(shù)據(jù)之前必須先對(duì)其加S鎖,在要修改數(shù)據(jù)之前必須先對(duì)其加X鎖,直到事務(wù)結(jié)束后才釋放所有鎖。由于三級(jí)封鎖協(xié)議強(qiáng)調(diào)即使事務(wù)讀完數(shù)據(jù)A之后也不釋放S鎖,從而使得別的事務(wù)無法更改數(shù)據(jù)A。三級(jí)封鎖協(xié)議不但防止了喪失修改和不讀“臟”數(shù)據(jù),而且防止了不可重復(fù)讀。一、二、三級(jí)封鎖協(xié)議比照方表12-8所示。表12-8一、二、三級(jí)封鎖協(xié)議比照12.3.3封鎖出現(xiàn)的問題及解決方法和操作系統(tǒng)中一樣,事務(wù)使用封鎖機(jī)制后,可能會(huì)產(chǎn)生活鎖、死鎖等問題,DBMS必須妥善地解決這些問題,才能保障系統(tǒng)的正常運(yùn)行。1.活鎖如果事務(wù)T1封鎖了數(shù)據(jù)R,T2事務(wù)又請(qǐng)求封鎖R,于是T2等待。T3也請(qǐng)求封鎖R,當(dāng)T1釋放了R上的封鎖之后系統(tǒng)首先批準(zhǔn)了T3的要求,T2仍然等待。然后T4又請(qǐng)求封鎖R,當(dāng)T3釋放了R上的封鎖之后系統(tǒng)又批準(zhǔn)了T4的請(qǐng)求,……,T2有可能永遠(yuǎn)等待。這種在多個(gè)事務(wù)請(qǐng)求對(duì)同一數(shù)據(jù)封鎖時(shí),使某一用戶總是處于等待的狀況稱為活鎖。如圖12-2所示。圖12-2活鎖示意圖解決活鎖問題的方法是采用先來先效勞的策略。當(dāng)多個(gè)事務(wù)請(qǐng)求封鎖同一數(shù)據(jù)對(duì)象時(shí),封鎖子系統(tǒng)按請(qǐng)求封鎖的先后次序?qū)κ聞?wù)排隊(duì),數(shù)據(jù)對(duì)象上的鎖一旦釋放就批準(zhǔn)申請(qǐng)隊(duì)列中第1個(gè)事務(wù)獲得鎖。2.死鎖在兩個(gè)或多個(gè)任務(wù)中,如果每個(gè)任務(wù)鎖定了其他任務(wù)試圖鎖定的資源,此時(shí)會(huì)造成這些任務(wù)永久阻塞,從而出現(xiàn)死鎖。圖12-3清楚地顯示了死鎖狀態(tài),其中:圖12-3死鎖示意圖任務(wù)T1具有資源A的鎖〔通過從A指向T1的箭頭指示〕,并請(qǐng)求資源B的鎖〔通過從T1指向B的箭頭指示〕。任務(wù)T2具有資源B的鎖〔通過從B指向T2的箭頭指示〕,并請(qǐng)求資源A的鎖〔通過從T2指向A的箭頭指示〕。因?yàn)檫@兩個(gè)任務(wù)都需要有資源可用才能繼續(xù),而這兩個(gè)資源又必須等到其中一個(gè)任務(wù)繼續(xù)才會(huì)釋放出來,所以陷入了死鎖狀態(tài)。下面再從表12-9的執(zhí)行序列上來進(jìn)一步分析死鎖的發(fā)生。表12-9死鎖T1T2XlockA....XlockB..XlockB.等待XlockA等待等待等待等待..表12-中,事務(wù)T1和T2都需要數(shù)據(jù)A和B,操作時(shí)Tl封鎖了數(shù)據(jù)A,T2封鎖了數(shù)據(jù)B;然后T1又請(qǐng)求封鎖B,T2又請(qǐng)求封鎖A;因T2已封鎖了B,故T1等待T2釋放B上的鎖。同理,因T1已封鎖了A,故T2等待T1釋放A上的鎖。由于Tl和T2都沒有獲得全部需要的數(shù)據(jù),所以它們不會(huì)結(jié)束,只能繼續(xù)等待。這種多事務(wù)交錯(cuò)等待的僵持局面就造成了死鎖的發(fā)生。12.3.4死鎖的預(yù)防和解除一般來講,死鎖是不可防止的。數(shù)據(jù)庫中解決死鎖問題主要有兩類方法:一類方法是采用一定措施來預(yù)防死鎖的發(fā)生;另一類方法是允許發(fā)生死鎖,然后采用一定手段定期診斷系統(tǒng)中有無死鎖,假設(shè)有那么解除之。1.死鎖的預(yù)防在數(shù)據(jù)庫系統(tǒng)中,產(chǎn)生死鎖的原因是兩個(gè)或多個(gè)事務(wù)都已封鎖了一些數(shù)據(jù)對(duì)象,然后又都請(qǐng)求對(duì)已為其他事務(wù)封鎖的數(shù)據(jù)對(duì)象加鎖,從而出現(xiàn)死鎖等待。防止死鎖的發(fā)生其實(shí)就是要破壞產(chǎn)生死鎖的條件。預(yù)防死鎖通常有兩種方法。(1)一次封鎖法一次封鎖法要求每個(gè)事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,否那么就不能繼續(xù)執(zhí)行。例如,在上圖的例子中,如果事務(wù)T1將數(shù)據(jù)對(duì)象A和B一次加鎖,T1就可以執(zhí)行下去,而T2等待。T1執(zhí)行完后釋放A,B上的鎖,T2繼續(xù)執(zhí)行。這樣就不會(huì)發(fā)生死鎖。一次封鎖法雖然可以有效地防止死鎖的發(fā)生,但也存在問題。第一,一次就將以后要用到的全部數(shù)據(jù)加鎖,勢(shì)必?cái)U(kuò)大了封鎖的范圍,從而降低了系統(tǒng)的并發(fā)度。第二,數(shù)據(jù)庫中數(shù)據(jù)是不斷變化的,原來不要求封鎖的數(shù)據(jù),在執(zhí)行過程中可能會(huì)變成封鎖對(duì)象,所以很難實(shí)現(xiàn)精確地確定每個(gè)事務(wù)所要封鎖的數(shù)據(jù)對(duì)象,只能采取擴(kuò)大封鎖范圍,將事務(wù)在執(zhí)行過程中可能要封鎖的數(shù)據(jù)對(duì)象全部加鎖,這就進(jìn)一步降低了并發(fā)度。(2)順序封鎖法順序封鎖法是預(yù)先對(duì)數(shù)據(jù)對(duì)象規(guī)定一個(gè)封鎖順序,所有事務(wù)都按這個(gè)順序執(zhí)行封鎖。在上例中,我們規(guī)定封鎖順是A,B,T1和T2都按此順序封鎖,即T2也必須先封鎖A。當(dāng)T2請(qǐng)求A的封鎖時(shí),由于T1已經(jīng)封鎖住A,T2就只能等待。T1釋放A,B上的鎖后,T2繼續(xù)運(yùn)行。這樣就不會(huì)發(fā)生死鎖。順序封鎖法同樣可以有效地防止死鎖,但也同樣存在問題。第一,數(shù)據(jù)庫系統(tǒng)中可封鎖的數(shù)據(jù)對(duì)象及其眾多,并且隨數(shù)據(jù)的插入、刪除等操作而不斷地變化,要維護(hù)這樣極多而且變化的資源的封鎖順序非常困難,本錢很高。第二,事務(wù)的封鎖請(qǐng)求可以隨著事務(wù)的執(zhí)行而動(dòng)態(tài)地決定,很難事先確定每一個(gè)事務(wù)要封鎖哪些對(duì)象,因此也就很難按規(guī)定的順序取施加封鎖。例如,規(guī)定數(shù)據(jù)對(duì)象的封鎖順序?yàn)锳,B,C,D,E。事務(wù)T3起初要求封鎖數(shù)據(jù)對(duì)象B,C,E,但當(dāng)它封鎖B,C后,才發(fā)現(xiàn)還需要封鎖A,這樣就破壞了封鎖順序??梢姡诓僮飨到y(tǒng)中廣為采用的預(yù)防死鎖的策略并不很適合數(shù)據(jù)庫的特點(diǎn),因此DBMS在解決死鎖的問題上更普遍采用的是診斷并解除死鎖的方法。2.死鎖的診斷數(shù)據(jù)庫系統(tǒng)中診斷死鎖的方法與操作系統(tǒng)類似,一般使用超時(shí)法或事務(wù)等待圖法?!?〕超時(shí)法如果一個(gè)事務(wù)的等待時(shí)間超過了規(guī)定的時(shí)限,就認(rèn)為發(fā)生了死鎖。超時(shí)法實(shí)現(xiàn)簡單,但其缺乏也很明顯。一是有可能誤判死鎖,事務(wù)因?yàn)槠渌蚴沟却龝r(shí)間超過時(shí)限,系統(tǒng)會(huì)誤認(rèn)為發(fā)生了死鎖。二是時(shí)限假設(shè)設(shè)置得太長,死鎖發(fā)生后不能及時(shí)發(fā)現(xiàn)?!?〕等待圖法事務(wù)等待圖是一個(gè)有向圖G=〔T,U〕。T為結(jié)點(diǎn)的集合,每個(gè)結(jié)點(diǎn)表示正運(yùn)行的事務(wù);U為邊的集合,每條邊表示事務(wù)等待的情況。假設(shè)T1等待T2,那么T1,T2之間劃一條有向邊,從T1指向T2。事務(wù)等待圖動(dòng)態(tài)地反映了所有事務(wù)的等待情況。并發(fā)控制子系統(tǒng)周期性地〔比方每隔1min〕檢測(cè)事務(wù)等待圖,如果發(fā)現(xiàn)圖中存在回路,那么表示系統(tǒng)中出現(xiàn)了死鎖。圖12-4事務(wù)等待圖圖12-4(a)中,事務(wù)T1等待T2,T2等待T1,產(chǎn)生了死鎖;圖12-4(b)中,事務(wù)T1等待T2,T2等待T3,T3等待T4,T4又等待T1,產(chǎn)生了死鎖;圖12-4(b)中,事務(wù)T3可能還等待T2,在大回路中又有小的回路。3.死鎖的解除DBMS的并發(fā)控制子系統(tǒng)一旦檢測(cè)到系統(tǒng)中存在死鎖,就要設(shè)法解除。通常采用的方法是選擇一個(gè)處理死鎖代價(jià)最小的事務(wù),將其撤銷,釋放此事務(wù)持有的所有的鎖,使其他事務(wù)得以繼續(xù)運(yùn)行下去。當(dāng)然,對(duì)撤銷的事務(wù)所執(zhí)行的數(shù)據(jù)修改操作必須加以恢復(fù)。SQLServer數(shù)據(jù)庫引擎自動(dòng)檢測(cè)SQLServer中的死鎖循環(huán)。數(shù)據(jù)庫引擎選擇一個(gè)會(huì)話作為死鎖犧牲品,然后終止當(dāng)前事務(wù)〔出現(xiàn)錯(cuò)誤〕來打斷死鎖。12.3.4封鎖的粒度封鎖粒度(Granularity)是指封鎖對(duì)象的大小。封鎖對(duì)象可以是邏輯單元,也可以是物理單元。以關(guān)系數(shù)據(jù)庫為例,封鎖對(duì)象可以是屬性值、屬性值的集合、元組、關(guān)系、直至整個(gè)數(shù)據(jù)庫;也可以是一些物理單元,例如頁(數(shù)據(jù)頁或索引項(xiàng))、塊等。封鎖粒度與系統(tǒng)的并發(fā)度和并發(fā)控制的開銷密切相關(guān)。封鎖的粒度越小,并發(fā)度越高,系統(tǒng)開銷也越大;封鎖的粒度越大,并發(fā)度越低,系統(tǒng)開銷也越小。一個(gè)系統(tǒng)應(yīng)同時(shí)支持多種封鎖粒度供不同的事務(wù)選擇,這種封鎖方法稱為多粒度封鎖(MultipleGranularityLocking)。選擇封鎖粒度時(shí)應(yīng)該綜合考慮封鎖開銷和并發(fā)度兩個(gè)因素,選擇適當(dāng)?shù)姆怄i粒度以求得最優(yōu)的效果。通常,需要處理大量元組的事務(wù)可以以關(guān)系為封鎖粒度;需要處理多個(gè)關(guān)系的大量元組的事務(wù)可以以數(shù)據(jù)庫為封鎖粒度;而對(duì)于一個(gè)處理少量元組的用戶事務(wù),以元組為封鎖粒度比較適宜。12.3.5并發(fā)調(diào)度的可串行性計(jì)算機(jī)系統(tǒng)對(duì)并發(fā)事務(wù)中并發(fā)操作的調(diào)度是隨機(jī)的,而不同的調(diào)度可能會(huì)產(chǎn)生不同的結(jié)果。哪個(gè)結(jié)果是正確的,哪個(gè)是不正確的?如果一個(gè)事務(wù)運(yùn)行過程中沒有其它事務(wù)同時(shí)運(yùn)行,也就是說它沒有受到其它事務(wù)的干擾,那么就可以認(rèn)為該事務(wù)的運(yùn)行結(jié)果是正常的或者預(yù)想的。因此將所有事務(wù)串行起來的調(diào)度策略一定是正確的調(diào)度策略。雖然以不同的順序串行執(zhí)行事務(wù)可能會(huì)產(chǎn)生不同的結(jié)果,但不會(huì)將數(shù)據(jù)庫置于不一致狀態(tài),所以都是正確的。定義:多個(gè)事務(wù)的并發(fā)執(zhí)行是正確的,當(dāng)且僅當(dāng)其結(jié)果與按某一次序串行地執(zhí)行它們時(shí)的結(jié)果相同,我們稱這種調(diào)度策略為可串行化〔Serializable〕的調(diào)度。可串行性〔Serializability〕是并發(fā)事務(wù)正確性的準(zhǔn)那么。按這個(gè)準(zhǔn)那么規(guī)定,一個(gè)給定的并發(fā)調(diào)度,當(dāng)且僅當(dāng)它是可串行化的,才認(rèn)為是正確調(diào)度。例如,現(xiàn)在有兩個(gè)事務(wù),分別包含以下操作:事務(wù)T1:讀B;A=B+1;寫回A;事務(wù)T2:讀A;B=A+1;寫回B;假設(shè)A,B的初值均為2。按T1→T2次序執(zhí)行結(jié)果為A=3,B=4;按T2→T1次序執(zhí)行結(jié)果為B=3,A=4。圖12-5給出了對(duì)這兩個(gè)事務(wù)的三種不同的調(diào)度策略。圖12-5〔a〕和〔b〕為兩種不同的串行調(diào)度策略,雖然執(zhí)行結(jié)果不同,但它們都是正確的調(diào)度;圖12-5〔c〕產(chǎn)兩個(gè)事務(wù)是交錯(cuò)執(zhí)行的;由于其執(zhí)行結(jié)果與〔a〕,〔b〕的結(jié)果都不同,所以是錯(cuò)誤的調(diào)度;圖12-5〔d〕中兩個(gè)事務(wù)也是交錯(cuò)執(zhí)行的,其執(zhí)行結(jié)果與串行調(diào)度〔a〕執(zhí)行結(jié)果相同,所以是正確的調(diào)度。T1T2T1T2T1T2T1T2SlockBSlockASlockB
SlockB
Y=B=2X=A=3Y=B=2
Y=B=2
UnlockBUnlockA
SlockAUnlockB
XlockAXlockB
X=A=2XlockA
A=Y+1B=X+1UnlockB
SlockA寫回A(=3)寫回B(=4)
UnlockAA=Y+1等待UnlockAUnlockBXlockA
寫回A(=3)等待SlockASlockBA=Y+1
UnlockA等待X=A=3Y=B=2寫回A(=3)
X=A=3UnlockAUnlockB
XlockBUnlockAXlockBXlockA
B=X+1XlockBB=X+1A=Y+1
寫回B(=3)B=X+1寫回B(=4)寫回A(=3)UnlockA
寫回B(=4)UnlockBUnlockAUnlockBUnlockB(a)串行調(diào)度(b)串行調(diào)度(c)不可串行化的調(diào)度(d)可串行化的調(diào)度圖12-5并發(fā)事務(wù)的不同調(diào)度為了保證并發(fā)操作的正確性,DBMS的并發(fā)控制機(jī)制必須提供一定的手段來保證調(diào)度是可串行化的。從理論上講,在某一事務(wù)執(zhí)行時(shí)禁止其它事務(wù)執(zhí)行的調(diào)度策略一定是可串行化的調(diào)度,這也是最簡單的調(diào)度策略,但這種方法實(shí)際上是不可取的,這使用戶不能充分共享數(shù)據(jù)庫資源。目前DBMS普遍采用封鎖方法實(shí)現(xiàn)并發(fā)操作調(diào)度的可串行性,從而保證調(diào)度的正確性。兩段鎖〔Two-PhaseLocking,簡稱2PL〕協(xié)議就是保證并發(fā)調(diào)度可串行性的封鎖協(xié)議。除此之外還有其它一些方法,如時(shí)標(biāo)方法、樂觀方法等來保證調(diào)度的正確性。12.3.6兩段鎖協(xié)議1.兩段鎖協(xié)議所謂兩段鎖協(xié)議是指所有事務(wù)必須分兩個(gè)階段對(duì)數(shù)據(jù)項(xiàng)加鎖和解鎖。第一階段是獲得封鎖,也稱為事務(wù)的擴(kuò)展階段。在這階段,事務(wù)在對(duì)任何數(shù)據(jù)進(jìn)行讀、寫操作之前,首先要申請(qǐng)并獲得對(duì)該數(shù)據(jù)的封鎖,事務(wù)可以申請(qǐng)獲得任何數(shù)據(jù)項(xiàng)上的任何類型的鎖,但是不能釋放任何鎖。第二階段是釋放封鎖,也稱為事務(wù)的收縮階段。在這階段,事務(wù)可以釋放任何數(shù)據(jù)項(xiàng)上的任何類型的鎖,但是在釋放一個(gè)封鎖之后,事務(wù)不再申請(qǐng)和獲得任何其它封鎖。例如,事務(wù)1的封鎖序列是:SlockA...SlockB…XlockC…UnlockB…UnlockA…UnlockC;事務(wù)2的封鎖序列是:SlockA...UnlockA…SlockB…XlockC…UnlockC…UnlockB;那么事務(wù)1遵守兩段封鎖協(xié)議,而事務(wù)2不遵守兩段封鎖協(xié)議。可以證明,假設(shè)并發(fā)執(zhí)行的所有事務(wù)均遵守兩段鎖協(xié)議,那么對(duì)這些事務(wù)的任何并發(fā)調(diào)度策略都是可串行化的。需要說明的是,事務(wù)遵守兩段鎖協(xié)議是可串行化調(diào)度的充分條件,而不是必要條件。也就是說;假設(shè)并發(fā)事務(wù)都遵守兩段鎖協(xié)議,那么對(duì)這些事務(wù)的任何并發(fā)調(diào)度策略都是可串行化的:假設(shè)對(duì)并發(fā)事務(wù)的一個(gè)調(diào)度是可串行化的,不一定所有事務(wù)都符合兩段鎖協(xié)議。在圖12-6中,〔a〕和〔b〕都是可串行化的調(diào)度,但〔a〕中T1和T2都遵守兩段鎖協(xié)議,〔b〕中T1和T2不遵守兩段鎖協(xié)議。在圖12-6中,〔c〕不是可串行化的調(diào)度,〔c〕中的T1和T2也比遵守兩段鎖協(xié)議。又如圖12-5中〔d〕是可串行化的調(diào)度,但T1和T2也不遵守兩段鎖協(xié)議。另外要注意兩段鎖協(xié)議和防止死鎖的一次封鎖法的異同之處。一次封鎖法要求每個(gè)事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,否那么就不能繼續(xù)執(zhí)行,因此一次封鎖法遵守兩段鎖協(xié)議;但是兩段鎖協(xié)議并不要求事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,因此遵守兩段鎖協(xié)議的事務(wù)可能發(fā)生死鎖,如圖12-7所示。T1T2T1T2T1T2SlockBSlockB讀B=2
讀B=2
SlockAY=B
Y=B
讀A=2XlockA
UnlockB
X=A
SlockAXlockA
UnlockA
等待
SlockASlockBA=Y+1等待
等待讀B=2寫回A=3等待A=Y+1等待Y=BXlockBUnlockA等待寫回A=3等待UnlockB等待UnlockB等待UnlockA等待XlockBSlockASlockAB=X+1讀A=3讀A=3寫回B=3Y=AX=AUnlockBXlockBUnlockAB=Y+1XlockBXlockA寫回B=4B=X+1A=Y+1UnlockB寫回B=4寫回A=3UnlockAUnlockBUnlockA(a)遵守兩段鎖協(xié)議(b)不遵守兩段鎖協(xié)議(c)不遵守兩段鎖協(xié)議圖12-6可串行化調(diào)度2.兩段鎖協(xié)議與防止死鎖的一次封鎖法的比較一次封鎖法要求每個(gè)事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,否那么就不能繼續(xù)執(zhí)行,因此一次封鎖法遵守兩段鎖協(xié)議,但是兩段鎖協(xié)議并不要求事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,因此遵守兩段鎖協(xié)議的事務(wù)可能發(fā)生死鎖。T1T2SlockB
讀B=2
SlockA
讀A=2XlockA
等待XlockB等待等待圖12-7遵守兩段鎖協(xié)議的事務(wù)發(fā)生死鎖3.兩段鎖協(xié)議與三級(jí)封鎖協(xié)議的比較兩類不同目的的協(xié)議。兩段鎖協(xié)議:保證并發(fā)調(diào)度的正確性三級(jí)封鎖協(xié)議:在不同程度上保證數(shù)據(jù)一致性遵守第三級(jí)封鎖協(xié)議必然遵守兩段協(xié)議。12.3SQLServer的并發(fā)控制機(jī)制12.3.1并發(fā)控制的類型當(dāng)許多人試圖同時(shí)修改數(shù)據(jù)庫中的數(shù)據(jù)時(shí),必須實(shí)現(xiàn)一個(gè)控制系統(tǒng),使一個(gè)人所做的修改不會(huì)對(duì)他人所做的修改產(chǎn)生負(fù)面影響。這稱為并發(fā)控制。并發(fā)控制理論根據(jù)建立并發(fā)控制的方法而分為3類:悲觀并發(fā)控制:一個(gè)鎖定系統(tǒng),可以阻止用戶以影響其他用戶的方式修改數(shù)據(jù)。如果用戶執(zhí)行的操作導(dǎo)致應(yīng)用了某個(gè)鎖,只有這個(gè)鎖的所有者釋放該鎖,其他用戶才能執(zhí)行與該鎖沖突的操作。這種方法之所以稱為悲觀并發(fā)控制,是因?yàn)樗饕糜跀?shù)據(jù)爭用劇烈的環(huán)境中,以及發(fā)生并發(fā)沖突時(shí)用鎖保護(hù)數(shù)據(jù)的本錢低于回滾事務(wù)的本錢的環(huán)境中。樂觀并發(fā)控制:在樂觀并發(fā)控制中,用戶讀數(shù)據(jù)時(shí)不鎖定數(shù)據(jù)。在執(zhí)行更新時(shí),系統(tǒng)進(jìn)行檢查,查看另一個(gè)用戶讀過數(shù)據(jù)后是否更改了數(shù)據(jù)。如果另一個(gè)用戶更新了數(shù)據(jù),將產(chǎn)生一個(gè)錯(cuò)誤。一般情況下,接收錯(cuò)誤信息的用戶將回滾事務(wù)并重新開始。該方法主要用在數(shù)據(jù)爭奪少的環(huán)境內(nèi),以及偶爾回滾事務(wù)的本錢超過讀數(shù)據(jù)時(shí)鎖定數(shù)據(jù)的本錢的環(huán)境內(nèi),因此稱該方法為樂觀并發(fā)控制。時(shí)標(biāo)并發(fā)控制:時(shí)標(biāo)和封鎖技術(shù)之間的根本區(qū)別是封鎖是使一組事務(wù)的并發(fā)執(zhí)行〔即交叉執(zhí)行〕同步,使用它等價(jià)于這些事務(wù)的某一串行操作;時(shí)標(biāo)法也是使用一組事務(wù)的交叉執(zhí)行同步,但是使它等價(jià)于這些事務(wù)的一個(gè)特定的串行執(zhí)行,即由時(shí)標(biāo)的時(shí)序所確定的一個(gè)執(zhí)行。如果發(fā)生沖突,是通過撤銷并重新啟動(dòng)一個(gè)事務(wù)解決的。事務(wù)重新啟動(dòng),那么賦予新的時(shí)標(biāo)。MicrosoftSQLServer支持一定范圍的并發(fā)控制。用戶通過為游標(biāo)上的連接或并發(fā)選項(xiàng)選擇事務(wù)隔離級(jí)別來指定并發(fā)控制的類型。這些特性可以使用Transact-SQL語句或通過數(shù)據(jù)庫應(yīng)用程序編程接口〔API,如ADO、ADO.NET、OLEDB和ODBC〕的屬性和特性來定義。12.3.2鎖定和行版本控制當(dāng)多個(gè)用戶同時(shí)訪問數(shù)據(jù)時(shí),SQLServer2008數(shù)據(jù)庫引擎使用以下機(jī)制確保事務(wù)的完整性和保持?jǐn)?shù)據(jù)庫的一致性:鎖定每個(gè)事務(wù)對(duì)所依賴的資源〔如行、頁或表〕請(qǐng)求不同類型的鎖。鎖可以阻止其他事務(wù)以某種可能會(huì)導(dǎo)致事務(wù)請(qǐng)求鎖出錯(cuò)的方式修改資源。當(dāng)事務(wù)不再依賴鎖定的資源時(shí),它將釋放鎖。行版本控制當(dāng)啟用了基于行版本控制的隔離級(jí)別時(shí),數(shù)據(jù)庫引擎將維護(hù)修改的每一行的版本。應(yīng)用程序可以指定事務(wù)使用行版本查看事務(wù)或查詢開始時(shí)存在的數(shù)據(jù),而不是使用鎖保護(hù)所有讀取。通過使用行版本控制,讀取操作阻止其他事務(wù)的可能性將大大降低。鎖定和行版本控制可以防止用戶讀取未提交的數(shù)據(jù),還可以防止多個(gè)用戶嘗試同時(shí)更改同一數(shù)據(jù)。如果不進(jìn)行鎖定或行版本控制,對(duì)數(shù)據(jù)執(zhí)行的查詢可能會(huì)返回?cái)?shù)據(jù)庫中尚未提交的數(shù)據(jù),從而產(chǎn)生意外的結(jié)果。應(yīng)用程序可以選擇事務(wù)隔離級(jí)別,為事務(wù)定義保護(hù)級(jí)別,以防被其他事務(wù)所修改??梢詾楦鱾€(gè)Transact-SQL語句指定表級(jí)別的提示,進(jìn)一步定制行為以滿足應(yīng)用程序的要求。用戶可以通過啟用或禁用數(shù)據(jù)庫選項(xiàng)來控制是否實(shí)現(xiàn)行版本控制。下面介紹啟用基于行版本控制的隔離級(jí)別和使用基于行版本控制的隔離級(jí)別。〔1〕啟用基于行版本控制的隔離級(jí)別數(shù)據(jù)庫管理員可以通過在ALTERDATABASE語句中使用READ_COMMITTED_SNAPSHOT和ALLOW_SNAPSHOT_ISOLATION數(shù)據(jù)庫選項(xiàng)來控制行版本控制的數(shù)據(jù)庫級(jí)別設(shè)置。將READ_COMMITTED_SNAPSHOT數(shù)據(jù)庫選項(xiàng)設(shè)置為ON后,用于支持該選項(xiàng)的機(jī)制將立即激活。設(shè)置READ_COMMITTED_SNAPSHOT選項(xiàng)時(shí),數(shù)據(jù)庫中只允許存在執(zhí)行ALTERDATABASE命令的連接。在ALTERDATABASE完成之前,數(shù)據(jù)庫中不允許有其他翻開的連接。數(shù)據(jù)庫不必處于單用戶模式。下面的Transact-SQL語句將啟用READ_COMMITTED_SNAPSHOT:ALTERDATABASEstu_infoSETREAD_COMMITTED_SNAPSHOTON;如果ALLOW_SNAPSHOT_ISOLATION數(shù)據(jù)庫選項(xiàng)設(shè)置為ON,那么數(shù)據(jù)庫中數(shù)據(jù)已修改的所有活動(dòng)事務(wù)完成之前,MicrosoftSQLServer數(shù)據(jù)庫引擎實(shí)例不會(huì)為已修改的數(shù)據(jù)生成行版本。如果存在活動(dòng)的修改事務(wù),SQLServer將把該選項(xiàng)的狀態(tài)設(shè)置為PENDING_ON。所有修改事務(wù)完成后,該選項(xiàng)的狀態(tài)更改為ON。在該選項(xiàng)完全處于ON狀態(tài)之前,用戶無法在數(shù)據(jù)庫中啟動(dòng)快照事務(wù)。數(shù)據(jù)庫管理員將ALLOW_SNAPSHOT_ISOLATION選項(xiàng)設(shè)置為OFF后,數(shù)據(jù)庫將跳過PENDING_OFF狀態(tài)。下面的Transact-SQL語句將啟用ALLOW_SNAPSHOT_ISOLATION:ALTERDATABASEstu_infoSETALLOW_SNAPSHOT_ISOLATIONON;〔2〕使用基于行版本控制的隔離級(jí)別行版本控制框架在SQLServer中始終處于啟用狀態(tài),并被多個(gè)功能使用。它除了提供基于行版本控制的隔離級(jí)別之外,還用于支持對(duì)觸發(fā)器和多個(gè)活動(dòng)結(jié)果集(MARS)會(huì)話的修改,以及ONLINE索引操作的數(shù)據(jù)讀取?;谛邪姹究刂频母綦x級(jí)別是在數(shù)據(jù)庫級(jí)別上啟用的。訪問已啟用數(shù)據(jù)庫的對(duì)象的任何應(yīng)用程序可以使用以下隔離級(jí)別運(yùn)行查詢:?已提交讀隔離級(jí)別,通過將READ_COMMITTED_SNAPSHOT數(shù)據(jù)庫選項(xiàng)設(shè)置為ON來使用行版本控制,如下面的代碼例如所示:ALTERDATABASEAdventureWorks2008R2SETREAD_COMMITTED_SNAPSHOTON;為READ_COMMITTED_SNAPSHOT啟用數(shù)據(jù)庫后,在已提交讀隔離級(jí)別下運(yùn)行的所有查詢將使用行版本控制,這意味著讀取操作不會(huì)阻止更新操作。?快照隔離,通過將ALLOW_SNAPSHOT_ISOLATION數(shù)據(jù)庫選項(xiàng)設(shè)置為ON實(shí)現(xiàn),如下面的代碼例如所示:ALTERDATABASEAdventureWorks2008R2SETALLOW_SNAPSHOT_ISOLATIONON;12.3.3SQLServer鎖的粒度鎖是為防止其它事務(wù)訪問指定的資源,實(shí)現(xiàn)并發(fā)控制的主要手段。要加快事務(wù)的處理速度并縮短事務(wù)的等待時(shí)間,就要使事務(wù)鎖定的資源最小。SQLServer為使事務(wù)鎖定資源最小化提供了多粒度鎖。(1)行級(jí)鎖〔ROW〕表中的行是鎖定的最小空間資源。行級(jí)鎖是指事務(wù)操作過程中,鎖定一行或假設(shè)干行數(shù)據(jù)。(2)頁和頁級(jí)鎖〔PAGE〕在SQLServer中,除行外的最小數(shù)據(jù)單位是頁。一個(gè)頁有8KB,所有的數(shù)據(jù)、日志和索引都放在頁上。為了管理方便,表中的行不能跨頁存放,一行的數(shù)據(jù)必須在同一個(gè)頁上。頁級(jí)鎖是指在事務(wù)的操作過程中,無論事務(wù)處理多少數(shù)據(jù),每一次都鎖定一頁。(3)簇〔EXTENT〕和簇級(jí)鎖頁之上的空間管理單位是簇,一個(gè)簇有8個(gè)連續(xù)的頁。簇級(jí)鎖指事務(wù)占用一個(gè)簇,這個(gè)簇不能被其它事務(wù)占用。簇級(jí)鎖是一種特殊類型的鎖,只用在一些特殊的情況下。例如在創(chuàng)立數(shù)據(jù)庫和表時(shí),系統(tǒng)用簇級(jí)鎖分配物理空間。由于系統(tǒng)是按照簇分配空間的,系統(tǒng)分配空間時(shí)使用簇級(jí)鎖,可防止其它事務(wù)同時(shí)使用一個(gè)簇。(4)表級(jí)鎖〔TABLE〕表級(jí)鎖是一種主要的鎖。表級(jí)鎖是指事務(wù)在操縱某一個(gè)表的數(shù)據(jù)時(shí)鎖定了這些數(shù)據(jù)所在的整個(gè)表,其它事務(wù)不能訪問該表中的數(shù)據(jù)。當(dāng)事務(wù)處理的數(shù)量比較大時(shí),一般使用表級(jí)鎖。(5)數(shù)據(jù)庫級(jí)鎖〔DATABASE〕數(shù)據(jù)庫級(jí)鎖是指鎖定整個(gè)數(shù)據(jù)庫,防止其它任何用戶或者事務(wù)對(duì)鎖定的數(shù)據(jù)庫進(jìn)行訪問。這種鎖的等級(jí)最高,因?yàn)樗刂普麄€(gè)數(shù)據(jù)庫的操作。數(shù)據(jù)庫級(jí)鎖是一種非常特殊的鎖,它只用于數(shù)據(jù)庫的恢復(fù)操作。只要對(duì)數(shù)據(jù)庫進(jìn)行恢復(fù)操作,就需要將數(shù)據(jù)庫設(shè)置為單用戶模式,防止其它用戶對(duì)該數(shù)據(jù)庫進(jìn)行各種操作。SQLServer數(shù)據(jù)庫引擎中可以鎖定的資源如表12-10所示。表12-10SQLServer數(shù)據(jù)庫引擎可以鎖定的資源序號(hào)資源說明1RID用于鎖定堆中的單個(gè)行的行標(biāo)識(shí)符。2KEY索引中用于保護(hù)可序列化事務(wù)中的鍵范圍的行鎖。3PAGE數(shù)據(jù)庫中的8KB頁,例如數(shù)據(jù)頁或索引頁。4EXTENT一組連續(xù)的八頁,例如數(shù)據(jù)頁或索引頁。5HoBT堆或B樹。用于保護(hù)沒有聚集索引的表中的B樹(索引)或堆數(shù)據(jù)頁的鎖。6TABLE包括所有數(shù)據(jù)和索引的整個(gè)表。7FILE數(shù)據(jù)庫文件。8APPLICATION應(yīng)用程序?qū)S玫馁Y源。9METADATA元數(shù)據(jù)鎖。10ALLOCATION_UNIT分配單元。11DATABASE整個(gè)數(shù)據(jù)庫。12.3.4鎖模式MicrosoftSQLServer數(shù)據(jù)庫引擎使用不同的鎖模式鎖定資源,這些鎖模式確定了并發(fā)事務(wù)訪問資源的方式。表12-11顯示了數(shù)據(jù)庫引擎使用的資源鎖模式。表12-11數(shù)據(jù)庫引擎使用的資源鎖模式鎖模式說明共享(S)用于不更改或不更新數(shù)據(jù)的讀取操作,如SELECT語句。更新(U)用于可更新的資源中。防止當(dāng)多個(gè)會(huì)話在讀取、鎖定以及隨后可能進(jìn)行的資源更新時(shí)發(fā)生常見形式的死鎖。排他(X)用于數(shù)據(jù)修改操作,例如INSERT、UPDATE或DELETE。確保不會(huì)同時(shí)對(duì)同一資源進(jìn)行多重更新。意向用于建立鎖的層次結(jié)構(gòu)。意向鎖包含三種類型:意向共享(IS)、意向排他(IX)和意向排他共享(SIX)。架構(gòu)在執(zhí)行依賴于表架構(gòu)的操作時(shí)使用。架構(gòu)鎖包含兩種類型:架構(gòu)修改(Sch-M)和架構(gòu)穩(wěn)定性(Sch-S)。大容量更新(BU)在向表進(jìn)行大容量數(shù)據(jù)復(fù)制且指定了TABLOCK提示時(shí)使用。鍵范圍當(dāng)使用可序列化事務(wù)隔離級(jí)別時(shí)保護(hù)查詢讀取的行的范圍。確保再次運(yùn)行查詢時(shí)其他事務(wù)無法插入符合可序列化事務(wù)的查詢的行。〔1〕共享鎖共享鎖〔S鎖〕允許并發(fā)事務(wù)在封閉式并發(fā)控制下讀取(SELECT)資源。資源上存在
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 私人教練與學(xué)員健身成果合同
- 租賃住宅合同范本簡版
- 南京勞動(dòng)合同模板合同范本(勞務(wù)派遣律師定制)
- 資產(chǎn)收購合同
- 歷史文化名城拍攝許可合同
- 廣告宣傳合同范文
- 商品供應(yīng)合同范本
- 批發(fā)業(yè)渠道管理與拓展考核試卷
- D打印技術(shù)在汽車輕量化設(shè)計(jì)的應(yīng)用考核試卷
- 工業(yè)控制計(jì)算機(jī)在智能機(jī)器人編程與控制中的實(shí)踐考核試卷
- 2023年全國各省高考詩歌鑒賞真題匯總及解析
- 四年級(jí)上冊(cè)音樂《楊柳青》課件PPT
- 安徽省廬陽區(qū)小升初語文試卷含答案
- 全國2017年4月自考00043經(jīng)濟(jì)法概論(財(cái)經(jīng)類)試題及答案
- 東鄉(xiāng)族學(xué)習(xí)課件
- 蘇教版六年級(jí)數(shù)學(xué)下冊(cè)《解決問題的策略2》優(yōu)質(zhì)教案
- GB/T 9846-2015普通膠合板
- GB/T 32348.1-2015工業(yè)和商業(yè)用電阻式伴熱系統(tǒng)第1部分:通用和試驗(yàn)要求
- 英國文學(xué)8.2講解Sonnet18
- GB/T 13470-1992通風(fēng)機(jī)系統(tǒng)經(jīng)濟(jì)運(yùn)行
- 公民個(gè)人信息安全的刑法保護(hù)論文
評(píng)論
0/150
提交評(píng)論