SQL Server中四類事務併發問題的例項再現

2021-04-03 02:12:44 字數 4484 閱讀 5409

sql server中四類事務併發問題的例項再現

本篇文章將用例項再現資料庫訪問中四類併發問題,希望能讓初學者能對事務的並行性有進一步的理解。

首先,讓我們先來了解一下並行問題以及事務隔離級別這兩個概念。

在資料庫中,假設如果沒有鎖定且多個使用者同時訪問乙個資料庫,則當他們的事務同時使用相同的資料時可能會發生問題。併發問題包括: 

下面讓我們稍花點時間來解釋一下這四類問題:

1、丟失更新

當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最後的更新將重寫由其它事務所做的更新,這將導致資料丟失。

2、未確認的相關性(髒讀)

當第二個事務選擇其它事務正在更新的行時,會發生未確認的相關性問題。第二個事務正在讀取的資料還沒有確認並且可能由更新此行的事務所更改。

3、不一致的分析(非重複讀)

當第二個事務多次訪問同一行而且每次讀取不同的資料時,會發生不一致的分析問題。不一致的分析與未確認的相關性類似,因為其它事務也是正在更改第二個事務正在讀取的資料。然而,在不一致的分析中,第二個事務讀取的資料是由已進行了更改的事務提交的。而且,不一致的分析涉及多次(兩次或更多)讀取同一行,而且每次資訊都由其它事務更改;因而該行被非重複讀取。

4、幻像讀

當對某行執行插入或刪除操作,而該行屬於某個事務正在讀取的行的範圍時,會發生幻像讀問題。事務第一次讀的行範圍顯示出其中一行已不復存在於第二次讀或後續讀中,因為該行已被其它事務刪除。同樣,由於其它事務的插入操作,事務的第二次或後續讀顯示有一行已不存在於原始讀中。

上述四個問題都會引起資料的不一致性。我們把事務準備接受不一致資料的級別稱為隔離級別。隔離級別是乙個事務必須與其它事務進行隔離的程度。較低的隔離級別可以增加併發,但代價是降低資料的正確性。相反,較高的隔離級別可以確保資料的正確性,但可能對併發產生負面影響。應用程式要求的隔離級別確定了

sql server 使用的鎖定行為。

sql-92 定義了下列四種隔離級別,sql server 支援所有這些隔離級別:

下表(1)列出了四種隔離級別允許不同型別的行為。

隔離級別

髒讀不可重複讀取

幻像未提交讀是是

是提交讀否是

是可重複讀否否

是可序列讀否否

為了再現以上四類問題,我們必須做一些準備工作:

1、請用下面的指令碼建立測試用的表。

--建立測試用資料庫test

create database test

go--建立測試用表

use test

gocreate table 帳戶表

(帳號 char(4),

餘額 int)go

insert 帳戶表

select 'a',100

union all

select 'b',200

2、請開啟兩個查詢分析器程式,意在開啟兩個連線,模擬兩個並行的事務。以下簡稱連線一和連線二。

測試正式開始:

(1)丟失更新的再現

先看下面這個例子:

--在第乙個連線中執行以下語句

begin tran

update 帳戶表 set 餘額=101 where 帳號='a' 

waitfor delay '00:00:10' --等待10秒

commit tran

--接著馬上使用第二連線執行下面的語句

begin tran

update 帳戶表 set 餘額=102 where 帳號='a' 

commit tran

我們會發現第二個連線裡面的事務不能立刻執行,必須等待第一連線的事務完成之後才能執行下去。

這樣就避免了「丟失更新」的問題,否則的話就會產生「丟失更新」的問題了。

丟失更新的問題是最為嚴重的一類問題,由表一可知,無論使用哪一種事務隔離級別,都不允許丟失更新的問題,因此該類問題無法再現。

(2)未確認的相關性(髒讀)的再現

由表1可知,當事務的隔離級別為未提交讀(read uncommitted)的時候,允許髒讀。

--在第乙個連線中執行以下語句

begin tran

update 帳戶表 set 餘額=103 where 帳號='a' 

waitfor delay '00:00:10' --等待10秒

update 帳戶表 set 餘額=104 where 帳號='a'

commit tran

--接著馬上使用第二連線執行下面的語句

set transaction isolation level read uncommitted

begin tran

select 餘額 from 帳戶表 where 帳號='a' 

commit tran

我們會發現第二個連線的語句會立即返回,結果是103,但遺憾的是它讀取的是髒資料。

如果我們把第二個連線的事務隔離級別設定為 read committed、repeatable read 或者serializable,都可以避免「髒讀」的發生。

(3)不一致的分析(非重複讀)的再現

由表1可知,當事務的隔離級別為未提交讀(read uncommitted)或者read committed的時候,便可在現此問題。

請測試下面這個例子(假設帳號a的餘額為100):

--在第乙個連線中執行以下語句

set transaction isolation level read committed

--或者 set transaction isolation level read uncommitted

begin tran

select 餘額 from 帳戶表 where 帳號='a'

waitfor delay '00:00:10' --等待10秒

select 餘額 from 帳戶表 where 帳號='a'

commit tran

--接著馬上使用第二連線執行下面的語句

begin tran

update 帳戶表 set 餘額=10 where 帳號='a'

commit tran

我們會發現第乙個連線中兩次返回帳號a的餘額不一樣,第一次是100,第二次返回的是10,這是典型的「非重複讀」問題。

如果把連線一的事務隔離級別設定為repeatable read 或者serializable,可防止此類問題。

(3)不一致的分析(非重複讀)的再現

由表1可知,當事務的隔離級別為未提交讀(read uncommitted)或者read committed的時候,便可在現此問題。

先看下面這個例子(假設帳號a的餘額為100):

--在第乙個連線中執行以下語句

set transaction isolation level read committed

--或者 set transaction isolation level read uncommitted

begin tran

select 餘額 from 帳戶表 where 帳號='a'

waitfor delay '00:00:10' --等待10秒

select 餘額 from 帳戶表 where 帳號='a'

commit tran

--接著馬上使用第二連線執行下面的語句

begin tran

update 帳戶表 set 餘額=10 where 帳號='a'

commit tran

我們會發現第乙個連線中兩次返回帳號a的餘額不一樣,第一次是100,第二次返回的是10,這是典型的「非重複讀」問題。

如果把連線一的事務隔離級別設定為repeatable read 或者serializable,可防止此類問題。

(4)幻像讀的再現

由表1可知,當事務的隔離級別為read uncommitted或者read committed或者repeatable read的時候,便可再現此問題。

先看下面這個例子(假設帳號a的餘額為100):

--在第乙個連線中執行以下語句

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

--接著馬上使用第二連線執行下面的語句

begin tran

insert into 帳戶表 values('c','300')

commit tran

我們會發現第乙個連線中在同乙個事務中,同樣的查詢語句兩次返回的結果集不一樣,第二次返回的結果集中多了一條帳號為c的帳號,這是典型的「幻像讀」問題。只有將連線一的事務隔離級別設定為serializable,才可防止此類問題。

《Inside C 》筆記 四 類

類是對資料結構和演算法的封裝。一 類成員 類成員包括以下幾類,作者在後面的章節會詳細講解。字段 用來儲存資料,可用static readonly const來修飾 方法 運算元據的 屬性 用來控制對類內部變數的訪問 常量 索引器 事件和運算子。二 訪問修飾符 public 可被外部的類和派生類訪問 ...

C 中的四類強制轉換?

c 中的四類強制轉換?例 class classa virtual void functiona class classb class classc public classa,public classb classc aobject classa pa aobject classb pb aobj...

類(四) 類的作用域

基於 c primer p253 在類的作用域之外,普通的資料和函式成員只能由物件 引用或者指標使用成員訪問運算子來訪問。對於類型別成員則是喲個作用域運算子訪問。screen pos ht 24,wd 80 使用 screen 定義的 pos 型別 screen scr ht,wd,screen p...