無法獲得資料庫 model 上的排他鎖 解決方法

2021-07-10 22:38:57 字數 3862 閱讀 2772

解決思路:先查出占用model資料庫的程序id,然後使用kill命令「殺掉」程序

解決方法:(在查詢分析器中執行以下**即可)

use master

declare @sql varchar(100)

while 1=1

begin

select top 1 @sql = 'kill '+cast(spid as varchar(3))

from master..sysprocesses

where spid > 50 and spid <> @@spid

if @@rowcount = 0

break

exec(@sql)

end

死鎖是指在某組資源中,兩個或兩個以上的執行緒在執行過程中,在爭奪某一資源時而造成互相等待的現象,若無外力的作用下,它們都將無法推進下去,死時就可能會產生死鎖,這些永遠在互相等待的程序稱為死鎖執行緒。簡單的說,程序a等待程序b釋放他的資源,b又等待a釋放他的資源,這樣互相等待就形成死鎖。

如在資料庫中,如果需要對一條資料進行修改,首先資料庫管理系統會在上面加鎖,以保證在同一時間只有乙個事務能進行修改操作。如事務1的執行緒 t1具有表a上的排它鎖,事務2的執行緒t2 具有表b上的排它鎖,並且之後需要表a上的鎖。事務2無法獲得這一鎖,因為事務1已擁有它。事務2被阻塞,等待事務1。然後,事務1需要表b的鎖,但無法獲得鎖,因為事務2將它鎖定了。事務在提交或回滾之前不能釋放持有的鎖。因為事務需要對方控制的鎖才能繼續操作,所以它們不能提交或回滾,這樣資料庫就會發生死鎖了。

如在編寫儲存過程的時候,由於有些儲存過程事務性的操作比較頻繁,如果先鎖住表a,再鎖住表b,那麼在所有的儲存過程中都要按照這個順序來鎖定它們。如果無意中某個儲存過程中先鎖定表b,再鎖定表a,這可能就會導致乙個死鎖。而且死鎖一般是不太容易被發現的。

如果伺服器上經常出現這種死鎖情況,就會降低伺服器的效能,所以應用程式在使用的時候,我們就需要對其進行跟蹤,使用sp_who和sp_who2來確定可能是哪些使用者阻塞了其他使用者。我們還可以根據以下**檢視資料庫死鎖的儲存過程sp_who_lock:

use master

gocreate procedure sp_who_lock

asbegin

declare @spid int,@bl int,

@inttransactioncountonentry int,

@introwcount int,

@intcountproperties int,

@intcounter int

create table #tmp_lock_who (

id int identity(1,1),

spid smallint,

bl smallint)

if @@error<>0 return @@error

insert into #tmp_lock_who(spid,bl) select 0 ,blocked

from (select * from sysprocesses where blocked>0 ) a

where not exists(select * from (select * from sysprocesses where blocked>0 ) b

where a.blocked=spid)

union select spid,blocked from sysprocesses where blocked>0

if @@error<>0 return @@error

-- 找到臨時表的記錄數

select @intcountproperties = count(*),@intcounter = 1

from #tmp_lock_who

if @@error<>0 return @@error

if @intcountproperties=0

select '現在沒有阻塞和死鎖資訊' as message

-- 迴圈開始

while @intcounter <= @intcountproperties

begin

-- 取第一條記錄

select @spid = spid,@bl = bl

from #tmp_lock_who where id = @intcounter

begin

if @spid =0

select '引起資料庫死鎖的是: '+ cast(@bl as varchar(10)) + '程序號,其執行的sql語法如下'

else

select '程序號spid:'+ cast(@spid as varchar(10))+ '被' + '程序號spid:'+ cast(@bl as varchar(10)) +'阻塞,其當前程序執行的sql語法如下'

dbcc inputbuffer (@bl )

end

-- 迴圈指標下移

set @intcounter = @intcounter + 1

enddrop table #tmp_lock_who

return 0

end

我們只需要通過在查詢分析器裡面執行sp_who_lock,就可以具體捕捉到執行的堵塞程序,這時我們就可以對對應的sql語句或者儲存過程進行效能上面的改進及設計。

所以我們在資料庫設計的時候,雖然不能完全避免死鎖,但可以使死鎖的數量儘量減少。增加事務的吞吐量並減少系統開銷,因為只有很少的事務,所以就得遵循下面的原則:

按同一順序訪問物件

如果所有併發事務按同一順序訪問物件,則發生死鎖的可能性會降低。在寫sql語句或儲存過程的時候,就需要按照順序在兩個併發事務中先獲得表a上的鎖,然後獲得表b上的鎖,當第乙個事務完成之前,另乙個事務被阻塞在表a上。第乙個事務提交或回滾後,第二個事務繼續進行,而不能在語句裡面寫先獲得表b上的鎖,然後再獲得表a的鎖。

避免事務中的使用者互動

避免編寫包含使用者互動的事務,因為執行沒有使用者互動的批處理的速度要遠遠快於使用者手動響應查詢的速度,例如答覆應用程式請求引數的提示。例如,如果事務正在等待使用者輸入,而使用者就去做別的事了,則使用者將此事務掛起使之不能完成。這樣將降低系統的吞吐量,因為事務持有的任何鎖只有在事務提交或回滾時才會釋放。即使不出現死鎖的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。

保持事務簡短並在乙個批處理中

在同一資料庫中併發執行多個需要長時間執行的事務時通常發生死鎖。事務執行時間越長,其持有排它鎖或更新鎖的時間也就越長,從而堵塞了其它活動並可能導致死鎖。保持事務在乙個批處理中,可以最小化事務的網路通訊往返量,減少完成事務可能的延遲並釋放鎖。

使用低隔離級別

確定事務是否能在更低的隔離級別上執行。執行提交讀允許事務讀取另乙個事務已讀取(未修改)的資料,而不必等待第乙個事務完成。使用較低的隔離級別(例如提交讀)而不使用較高的隔離級別(例如可序列讀)可以縮短持有共享鎖的時間,從而降低了鎖定爭奪。

使用繫結連線

使用繫結連線使同一應用程式所開啟的兩個或多個連線可以相互合作。次級連線所獲得的任何鎖可以象由主連線獲得的鎖那樣持有,反之亦然,因此不會相互阻塞。

下面有一些對死鎖發生的一些建議:

(1)對於頻繁使用的表使用集簇化的索引;

(2)設法避免一次性影響大量記錄的t-sql語句,特別是insert和update語句;

(3)設法讓update和delete語句使用索引;

(4)使用巢狀事務時,避免提交和回退衝突;

(5)對一些資料不需要及時讀取更新值的表在寫sql的時候在表後台加上(nolock),如:select * from tablea(nolock)

無法獲得資料庫 model 上的排他鎖 解決辦法

解決方法 在查詢分析器中執行如下 即可 declare sql varchar 100 while 1 1 begin select top 1 sql kill cast spid as varchar 3 from master.sysprocesses where spid 50 and sp...

無法獲得資料庫 model 上的排他鎖 解決辦法

問題 執行 transact sql 語句或批處理時發生了異常。microsoft.sqlserver.connectioninfo 無法獲得資料庫 model 上的排他鎖。請稍後重試該操作 解決思路 使用select spid from master.sys.sysprocesses 如果是200...

無法獲得資料庫 model 上的排他鎖 解決方法

原文 解決思路 先查出占用model資料庫的程序id,然後使用kill命令 殺掉 程序 解決方法 在查詢分析器中執行以下 即可 use master declare sql varchar 100 while 1 1 begin select top 1 sql kill cast spid as ...