C#程序中避免並發控制:
1.多線程的工作隊列
http://www.cnblogs.com/miniwiki/archive/2010/07/09/1774583.html2.SmartThreadPool的QueueWorkItem,方法http://www.lingdonge.com/csharp/33.html
http://support.microsoft.com/kb/832524/zh-cn
SQL Server中解決死鎖的新方法介紹
數據庫 操作的死鎖是不可避免的,本文並不打算討論死鎖如何產生,重點在於解決死鎖,通過SQL Server2005, 現在似乎有了一種新的解決辦法。
將下面的SQL語句放在兩個不同的連接里面,並且在5秒內同時執行,將會發生死鎖。
use Northwindbegin tran insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@#commitprint @#end tran@# |
SQL Server對付死鎖的辦法是犧牲掉其中的一個,拋出異常,並且回滾事務。在SQL Server 2000,語句一旦發生異常,T-SQL將不會繼續運行,上面被犧牲的連接中, print @#end tran@#語句將不會被運行,所以我們很難在SQL Server 2000的T-SQL中對死鎖進行進一步的處理。
現在不同了,SQL Server 2005可以在T-SQL中對異常進行捕獲,這樣就給我們提供了一條處理死鎖的途徑:
下面利用的try ... catch來解決死鎖。
SET XACT_ABORT ONdeclare @r intset @r = 1while @r <= 3begin begin tran begin try insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@# commit break end try begin catch rollback waitfor delay @#00:00:03@# set @r = @r + 1 continue end catchend |
解決方法當然就是重試,但捕獲錯誤是前提。rollback后面的waitfor不可少,發生沖突后需要等待一段時間,@retry數目可以調整以應付不同的要求。
但是現在又面臨一個新的問題 : 錯誤被掩蓋了,一但問題發生並且超過3次,異常卻不會被拋出。SQL Server 2005 有一個RaiseError語句,可以拋出異常,但卻不能直接拋出原來的異常,所以需要重新定義發生的錯誤,現在,解決方案 變成了這樣:
declare @r intset @r = 1while @r <= 3begin begin tran begin try insert into Orders(CustomerId) values(@#ALFKI@#) waitfor delay @#00:00:05@# select * from Orders where CustomerId = @#ALFKI@# commit break end try begin catch rollback waitfor delay @#00:00:03@# set @r = @r + 1 continue end catchendif ERROR_NUMBER() <> 0begin declare @ErrorMessage nvarchar(4000); declare @ErrorSeverity int; declare @ErrorState int; select @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState );end |
我希望將來SQL Server 2005能夠直接拋出原有異常,比如提供一個無參數的RaiseError。
因此方案有點臃腫,但將死鎖問題封裝到T-SQL中有助於明確職責,提高高層系統的清晰度。現在,對於DataAccess 的代碼,或許再也不需要考慮死鎖問題了
========================================================================
SQL Server2000中死鎖經驗總結
- 回滾,而回滾會取消事務執行的所有工作。
- 由於死鎖時回滾而由應用程序重新提交。
- 按同一順序訪問對象。
- 避免事務中的用戶交互。
- 保持事務簡短並在一個批處理中。
- 使用低隔離級別。
- 使用綁定連接。


































































































































設定跟蹤1204:
USE MASTER
DBCC TRACEON ( 1204 , - 1 )
顯示當前啟用的所有跟蹤標記的狀態:
DBCC TRACESTATUS( - 1 )
取消跟蹤1204:
DBCC TRACEOFF ( 1204 , - 1 )
在設定跟蹤1204后,會在數據庫的日志文件里顯示SQL Server數據庫死鎖時一些信息。但那些信息很難看懂,需要對照SQL Server聯機叢書仔細來看。根據PAG鎖要找到相關數據庫表的方法:
DBCC TRACEON ( 3604 )
DBCC PAGE (db_id,file_id,page_no)
DBCC TRACEOFF ( 3604 )
請參考sqlservercentral.com上更詳細的講解.但又從CSDN學到了一個找到死鎖原因的方法。我稍加修改, 去掉了游標操作並增加了一些提示信息,寫了一個系統存儲過程sp_who_lock.sql。代碼如下:
if exists (select * from dbo.sysobjects
where id = object_id(N ' [dbo].[sp_who_lock] ' )
and OBJECTPROPERTY(id, N ' IsProcedure ' ) = 1 )
drop procedure [dbo].[sp_who_lock]
GO
/* *******************************************************
// 學習到並改寫
// 說明 : 查看數據庫里阻塞和死鎖情況
******************************************************* */
use master
go
create procedure sp_who_lock
as
begin
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
end
drop table #tmp_lock_who
return 0
end
需要的時候直接調用:
sp_who_lock
就可以查出引起死鎖的進程和SQL語句.
SQL Server自帶的系統存儲過程sp_who和sp_lock也可以用來查找阻塞和死鎖, 但沒有這里介紹的方法好用。如果想知道其它tracenum參數的含義,請看http://www.sqlservercentral.com/ 文章
我們還可以設置鎖的超時時間(單位是毫秒), 來縮短死鎖可能影響的時間范圍:
例如:
use master
seelct @@lock_timeout
set lock_timeout 900000
-- 15分鍾
seelct @@lock_timeout
其實所有的死鎖最深層的原因就是一個:資源競爭
表現一:
一個用戶A 訪問表A(鎖住了表A),然后又訪問表B
另一個用戶B 訪問表B(鎖住了表B),然后企圖訪問表A
這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B,才能繼續,好了他老人家就只好老老實實在這等了
同樣用戶B要等用戶A釋放表A才能繼續這就死鎖了
解決方法:
這種死鎖是由於你的程序的BUG產生的,除了調整你的程序的邏輯別無他法
仔細分析你程序的邏輯,
1:盡量避免同時鎖定兩個資源
2: 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源.
表現二:
用戶A讀一條紀錄,然后修改該條紀錄
這是用戶B修改該條紀錄
這里用戶A的事務里鎖的性質由共享鎖企圖上升到獨占鎖(for update),而用戶B里的獨占鎖由於A有共享鎖存在所以必須等A釋
放掉共享鎖,而A由於B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,於是出現了死鎖。
這種死鎖比較隱蔽,但其實在稍大點的項目中經常發生。
解決方法:
讓用戶A的事務(即先讀后寫類型的操作),在select 時就是用Update lock
語法如下:
select * from table1 with(updlock) where ....
如何將數據庫中被鎖表解鎖
作者:佚名 文章來源:未知 點擊數:106 更新時間:2005-12-25
我們在操作數據庫的時候,有時候會由於操作不當引起數據庫表被鎖定,這么我們經常不知所措,不知怎么給這些表解鎖,在pl/sql Developer工具的的菜單“tools”里面的“sessions”可以查詢現在存在的會話,但是我們很難找到那個會話被鎖定了,想找到所以被鎖的會話就更難了,下面這叫查詢語句可以查詢出所以被鎖的會話。如下:
SELECT sn.username, m.SID,sn.SERIAL#, m.TYPE,
DECODE (m.lmode,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl.',
4, 'Share',
5, 'S/Row Excl.',
6, 'Exclusive',
lmode, LTRIM (TO_CHAR (lmode, '990'))
) lmode,
DECODE (m.request,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl.',
4, 'Share',
5, 'S/Row Excl.',
6, 'Exclusive',
request, LTRIM (TO_CHAR (m.request, '990'))
) request,
m.id1, m.id2
FROM v$session sn, v$lock m
WHERE (sn.SID = m.SID AND m.request != 0) --存在鎖請求,即被阻塞
OR ( sn.SID = m.SID --不存在鎖請求,但是鎖定的對象被其他會話請求鎖定
AND m.request = 0
AND lmode != 4
AND (id1, id2) IN (
SELECT s.id1, s.id2
FROM v$lock s
WHERE request != 0 AND s.id1 = m.id1
AND s.id2 = m.id2)
)
ORDER BY id1, id2, m.request;
通過以上查詢知道了sid和 SERIAL#就可以開殺了
alter system kill session 'sid,SERIAL#';
=======================================================