SQLServer中四類(lèi)事務(wù)并發(fā)問(wèn)題的示例分析

這篇文章將為大家詳細(xì)講解有關(guān)SQL Server中四類(lèi)事務(wù)并發(fā)問(wèn)題的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

專業(yè)成都網(wǎng)站建設(shè)公司,做排名好的好網(wǎng)站,排在同行前面,為您帶來(lái)客戶和效益!創(chuàng)新互聯(lián)建站為您提供成都網(wǎng)站建設(shè),五站合一網(wǎng)站設(shè)計(jì)制作,服務(wù)好的網(wǎng)站設(shè)計(jì)公司,成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)負(fù)責(zé)任的成都網(wǎng)站制作公司!

SQL Server中四類(lèi)事務(wù)并發(fā)問(wèn)題的實(shí)例再現(xiàn)

首先,讓我們先來(lái)了解一下并行問(wèn)題以及事務(wù)隔離級(jí)別這兩個(gè)概念。
在數(shù)據(jù)庫(kù)中,假設(shè)如果沒(méi)有鎖定且多個(gè)用戶同時(shí)訪問(wèn)一個(gè)數(shù)據(jù)庫(kù),則當(dāng)他們的事務(wù)同時(shí)使用相同的數(shù)據(jù)時(shí)可能會(huì)發(fā)生問(wèn)題。并發(fā)問(wèn)題包括: 

  • 丟失或覆蓋更新。

  • 未確認(rèn)的相關(guān)性(臟讀)。

  • 不一致的分析(非重復(fù)讀)。

  • 幻像讀。 

下面讓我們稍花點(diǎn)時(shí)間來(lái)解釋一下這四類(lèi)問(wèn)題:
1、丟失更新
當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí),會(huì)發(fā)生丟失更新問(wèn)題。每個(gè)事務(wù)都不知道其它事務(wù)的存在。最后的更新將重寫(xiě)由其它事務(wù)所做的更新,這將導(dǎo)致數(shù)據(jù)丟失。


2、未確認(rèn)的相關(guān)性(臟讀)
當(dāng)?shù)诙€(gè)事務(wù)選擇其它事務(wù)正在更新的行時(shí),會(huì)發(fā)生未確認(rèn)的相關(guān)性問(wèn)題。第二個(gè)事務(wù)正在讀取的數(shù)據(jù)還沒(méi)有確認(rèn)并且可能由更新此行的事務(wù)所更改。

3、不一致的分析(非重復(fù)讀)
當(dāng)?shù)诙€(gè)事務(wù)多次訪問(wèn)同一行而且每次讀取不同的數(shù)據(jù)時(shí),會(huì)發(fā)生不一致的分析問(wèn)題。不一致的分析與未確認(rèn)的相關(guān)性類(lèi)似,因?yàn)槠渌聞?wù)也是正在更改第二個(gè)事務(wù)正在讀取的數(shù)據(jù)。然而,在不一致的分析中,第二個(gè)事務(wù)讀取的數(shù)據(jù)是由已進(jìn)行了更改的事務(wù)提交的。而且,不一致的分析涉及多次(兩次或更多)讀取同一行,而且每次信息都由其它事務(wù)更改;因而該行被非重復(fù)讀取。

4、幻像讀
當(dāng)對(duì)某行執(zhí)行插入或刪除操作,而該行屬于某個(gè)事務(wù)正在讀取的行的范圍時(shí),會(huì)發(fā)生幻像讀問(wèn)題。事務(wù)第一次讀的行范圍顯示出其中一行已不復(fù)存在于第二次讀或后續(xù)讀中,因?yàn)樵撔幸驯黄渌聞?wù)刪除。同樣,由于其它事務(wù)的插入操作,事務(wù)的第二次或后續(xù)讀顯示有一行已不存在于原始讀中。

上述四個(gè)問(wèn)題都會(huì)引起數(shù)據(jù)的不一致性。我們把事務(wù)準(zhǔn)備接受不一致數(shù)據(jù)的級(jí)別稱為隔離級(jí)別。隔離級(jí)別是一個(gè)事務(wù)必須與其它事務(wù)進(jìn)行隔離的程度。較低的隔離級(jí)別可以增加并發(fā),但代價(jià)是降低數(shù)據(jù)的正確性。相反,較高的隔離級(jí)別可以確保數(shù)據(jù)的正確性,但可能對(duì)并發(fā)產(chǎn)生負(fù)面影響。應(yīng)用程序要求的隔離級(jí)別確定了 SQL
Server 使用的鎖定行為。

SQL-92 定義了下列四種隔離級(jí)別,SQL Server 支持所有這些隔離級(jí)別:

  • READ UNCOMMITTED---未提交讀(事務(wù)隔離的最低級(jí)別,僅可保證不讀取物理?yè)p壞的數(shù)據(jù))。

  • READ COMMITTED---提交讀(SQL Server 默認(rèn)級(jí)別)。

  • REPEATABLE READ---可重復(fù)讀。

  • SERIALIZABLE---可串行讀(事務(wù)隔離的最高級(jí)別,事務(wù)之間完全隔離)。

下表(1)列出了四種隔離級(jí)別允許不同類(lèi)型的行為。

隔離級(jí)別臟讀不可重復(fù)讀取幻像
未提交讀
提交讀
可重復(fù)讀
可串行讀


為了再現(xiàn)以上四類(lèi)問(wèn)題,我們必須做一些準(zhǔn)備工作:
1、請(qǐng)用下面的腳本創(chuàng)建測(cè)試用的表。

--創(chuàng)建測(cè)試用數(shù)據(jù)庫(kù)test
CREATE DATABASE test
GO
--創(chuàng)建測(cè)試用表
USE test
GO
CREATE TABLE 帳戶表
(
帳號(hào) CHAR(4),
余額 INT
)
GO
INSERT 帳戶表
SELECT 'A',100
UNION ALL
SELECT 'B',200


2、請(qǐng)開(kāi)啟兩個(gè)查詢分析器程序,意在開(kāi)啟兩個(gè)連接,模擬兩個(gè)并行的事務(wù)。以下簡(jiǎn)稱連接一和連接二。
測(cè)試正式開(kāi)始:
(1)丟失更新的再現(xiàn)

先看下面這個(gè)例子:

--在第一個(gè)連接中執(zhí)行以下語(yǔ)句

BEGIN TRAN
UPDATE 帳戶表 SET 余額=101 WHERE 帳號(hào)='A' 
WAITFOR DELAY '00:00:10' --等待10秒
COMMIT TRAN

--接著馬上使用第二連接執(zhí)行下面的語(yǔ)句

BEGIN TRAN
UPDATE 帳戶表 SET 余額=102 WHERE 帳號(hào)='A' 
COMMIT TRAN


我們會(huì)發(fā)現(xiàn)第二個(gè)連接里面的事務(wù)不能立刻執(zhí)行,必須等待第一連接的事務(wù)完成之后才能執(zhí)行下去。
這樣就避免了“丟失更新”的問(wèn)題,否則的話就會(huì)產(chǎn)生“丟失更新”的問(wèn)題了。

丟失更新的問(wèn)題是最為嚴(yán)重的一類(lèi)問(wèn)題,由表一可知,無(wú)論使用哪一種事務(wù)隔離級(jí)別,都不允許丟失更新的問(wèn)題,因此該類(lèi)問(wèn)題無(wú)法再現(xiàn)。

(2)未確認(rèn)的相關(guān)性(臟讀)的再現(xiàn)
由表1可知,當(dāng)事務(wù)的隔離級(jí)別為未提交讀(READ UNCOMMITTED)的時(shí)候,允許臟讀。

--在第一個(gè)連接中執(zhí)行以下語(yǔ)句

BEGIN TRAN
UPDATE 帳戶表 SET 余額=103 WHERE 帳號(hào)='A' 
WAITFOR DELAY '00:00:10' --等待10秒
UPDATE 帳戶表 SET 余額=104 WHERE 帳號(hào)='A'
COMMIT TRAN

--接著馬上使用第二連接執(zhí)行下面的語(yǔ)句
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN
SELECT 余額 FROM 帳戶表 WHERE 帳號(hào)='A' 
COMMIT TRAN


我們會(huì)發(fā)現(xiàn)第二個(gè)連接的語(yǔ)句會(huì)立即返回,結(jié)果是103,但遺憾的是它讀取的是臟數(shù)據(jù)。
如果我們把第二個(gè)連接的事務(wù)隔離級(jí)別設(shè)置為 READ COMMITTED、REPEATABLE READ 或者SERIALIZABLE,都可以避免“臟讀”的發(fā)生。

(3)不一致的分析(非重復(fù)讀)的再現(xiàn)
由表1可知,當(dāng)事務(wù)的隔離級(jí)別為未提交讀(READ UNCOMMITTED)或者READ COMMITTED的時(shí)候,便可在現(xiàn)此問(wèn)題。
請(qǐng)測(cè)試下面這個(gè)例子(假設(shè)帳號(hào)A的余額為100):

--在第一個(gè)連接中執(zhí)行以下語(yǔ)句

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
--或者 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN
SELECT 余額 FROM 帳戶表 WHERE 帳號(hào)='A'
WAITFOR DELAY '00:00:10' --等待10秒
SELECT 余額 FROM 帳戶表 WHERE 帳號(hào)='A'
COMMIT TRAN

--接著馬上使用第二連接執(zhí)行下面的語(yǔ)句
BEGIN TRAN
UPDATE 帳戶表 SET 余額=10 WHERE 帳號(hào)='A'
COMMIT TRAN

我們會(huì)發(fā)現(xiàn)第一個(gè)連接中兩次返回帳號(hào)A的余額不一樣,第一次是100,第二次返回的是10,這是典型的“非重復(fù)讀”問(wèn)題。
如果把連接一的事務(wù)隔離級(jí)別設(shè)置為REPEATABLE READ 或者SERIALIZABLE,可防止此類(lèi)問(wèn)題。


(3)不一致的分析(非重復(fù)讀)的再現(xiàn)
由表1可知,當(dāng)事務(wù)的隔離級(jí)別為未提交讀(READ UNCOMMITTED)或者READ COMMITTED的時(shí)候,便可在現(xiàn)此問(wèn)題。
先看下面這個(gè)例子(假設(shè)帳號(hào)A的余額為100):

--在第一個(gè)連接中執(zhí)行以下語(yǔ)句

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
--或者 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN
SELECT 余額 FROM 帳戶表 WHERE 帳號(hào)='A'
WAITFOR DELAY '00:00:10' --等待10秒
SELECT 余額 FROM 帳戶表 WHERE 帳號(hào)='A'
COMMIT TRAN

--接著馬上使用第二連接執(zhí)行下面的語(yǔ)句
BEGIN TRAN
UPDATE 帳戶表 SET 余額=10 WHERE 帳號(hào)='A'
COMMIT TRAN

我們會(huì)發(fā)現(xiàn)第一個(gè)連接中兩次返回帳號(hào)A的余額不一樣,第一次是100,第二次返回的是10,這是典型的“非重復(fù)讀”問(wèn)題。

如果把連接一的事務(wù)隔離級(jí)別設(shè)置為REPEATABLE READ 或者SERIALIZABLE,可防止此類(lèi)問(wèn)題。

(4)幻像讀的再現(xiàn)
由表1可知,當(dāng)事務(wù)的隔離級(jí)別為READ UNCOMMITTED或者READ COMMITTED或者REPEATABLE READ的時(shí)候,便可再現(xiàn)此問(wèn)題。
先看下面這個(gè)例子(假設(shè)帳號(hào)A的余額為100):

--在第一個(gè)連接中執(zhí)行以下語(yǔ)句

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
--或者 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
--或者 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRAN
SELECT * FROM 帳戶表 
WAITFOR DELAY '00:00:10' --等待10秒
SELECT * FROM 帳戶表 
COMMIT TRAN

--接著馬上使用第二連接執(zhí)行下面的語(yǔ)句
BEGIN TRAN
INSERT INTO 帳戶表 VALUES('C','300')
COMMIT TRAN

我們會(huì)發(fā)現(xiàn)第一個(gè)連接中在同一個(gè)事務(wù)中,同樣的查詢語(yǔ)句兩次返回的結(jié)果集不一樣,第二次返回的結(jié)果集中多了一條帳號(hào)為C的帳號(hào),這是典型的“幻像讀”問(wèn)題。只有將連接一的事務(wù)隔離級(jí)別設(shè)置為SERIALIZABLE,才可防止此類(lèi)問(wèn)題。
總結(jié):為了避免事務(wù)并發(fā)帶來(lái)的問(wèn)題,可采用較高的事務(wù)隔離級(jí)別,但因此會(huì)降低事務(wù)的并行性;反過(guò)來(lái)如果追求高的并行性而使用較低的事務(wù)隔離級(jí)別,又容易帶來(lái)并發(fā)的問(wèn)題。因此SQL Server采用默認(rèn)隔離級(jí)別是相對(duì)比較低的“READ COMMITTED”。在實(shí)際應(yīng)用的時(shí)候,采用何種隔離級(jí)別視具體情況而定,也可以采用顯式“上鎖”的方法控制事務(wù)隔離級(jí)別,具體方法請(qǐng)留意筆者的相關(guān)文章。

關(guān)于“SQL Server中四類(lèi)事務(wù)并發(fā)問(wèn)題的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

本文題目:SQLServer中四類(lèi)事務(wù)并發(fā)問(wèn)題的示例分析
網(wǎng)頁(yè)地址:http://muchs.cn/article16/jcphgg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化網(wǎng)站排名、面包屑導(dǎo)航、響應(yīng)式網(wǎng)站做網(wǎng)站、

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)