一個用戶A 訪問表A(鎖住了表A),然后又訪問表B;另一個用戶B 訪問表B(鎖住了表B),然后企圖訪問表A;這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B才能繼續,同樣用戶B要等用戶A釋放表A才能繼續,這就死鎖就產生了。
解決方法
這種死鎖比較常見,是由於程序的BUG產生的,除了調整的程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對於數據庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A后B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源。
2、死鎖的第二種情況
用戶A查詢一條紀錄,然后修改該條紀錄;這時用戶B修改該條紀錄,這時用戶A的事務里鎖的性質由查詢的共享鎖企圖上升到獨占鎖,而用戶B里的獨占鎖由於A有共享鎖存在所以必須等A釋放掉共享鎖,而A由於B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,於是出現了死鎖。這種死鎖比較隱蔽,但在稍大點的項目中經常發生。如在某項目中,頁面上的按鈕點擊后,沒有使按鈕立刻失效,使得用戶會多次快速點擊同一按鈕,這樣同一段代碼對數據庫同一條記錄進行多次操作,很容易就出現這種死鎖的情況。
解決方法
1、對於按鈕等控件,點擊后使其立刻失效,不讓用戶重復點擊,避免對同時對同一條記錄操作。
2、使用樂觀鎖進行控制。樂觀鎖大多是基於數據版本(Version)記錄機制實現。即為數據增加一個版本標識,在基於數據庫表的版本解決方案中,一般是通過為數據庫表增加一個“version”字段來實現。讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大於數據庫表當前版本號,則予以更新,否則認為是過期數據。樂觀鎖機制避免了長事務中的數據庫加鎖開銷(用戶A和用戶B操作過程中,都沒有對數據庫數據加鎖),大大提升了大並發量下的系統整體性能表現。 在其數據訪問引擎中內置了樂觀鎖實現。需要注意的是,由於樂觀鎖機制是在我們的系統中實現,來自外部系統的用戶更新操作不受我們系統的控制,因此可能會造成臟數據被更新到數據庫中。
3、使用悲觀鎖進行控制。悲觀鎖大多數情況下依靠數據庫的鎖機制實現,如Oracle的Select … for update語句,以保證操作最大程度的獨占性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。如一個金融系統,當某個操作員讀取用戶的數據,並在讀出的用戶數據的基礎上進行修改時(如更改用戶賬戶余額),如果采用悲觀鎖機制,也就意味着整個操作過程中(從操作員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操作員中途去煮咖啡的時間),數據庫記錄始終處於加鎖狀態,可以想見,如果面對成百上千個並發,這樣的情況將導致災難性的后果。所以,采用悲觀鎖進行控制時一定要考慮清楚。
3、死鎖的第三種情況
如果在事務中執行了一條不滿足條件的update語句,則執行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務執行后,就很容易產生死鎖和阻塞。類似的情況還有當表中的數據量非常龐大而索引建的過少或不合適的時候,使得經常發生全表掃描,最終應用系統會越來越慢,最終發生阻塞或死鎖。
解決方法
轉載於:http://blog.csdn.net/a137268431/article/details/50982371
一、DBCC死鎖分析
--DBCC捕獲死鎖信息方法
--1、打開跟蹤配置
USE master
GO
DBCC TRACEON(1222,-1)
GO
--2、查看狀態
DBCC TRACESTATUS(-1)
GO
--*跟蹤完畢,請執行下面關閉
DBCC TRACEOFF (1204, 1222, -1)
GO
--split into two stats,效果同上
DBCC TRACEOFF (1204,-1)
GO
DBCC TRACEOFF (1222,-1)
GO
--3、數據庫發生deadlock后,執行下面
EXEC sys.sp_readerrorlog
二、Profiler死鎖分析方法
1、啟動sql server profiler
2、勾選dealock選項
3、ctrl+F 搜索 deallock 字眼
4、選中deadlock項,提取事件數據,存儲為xdl,然后更名為xml,打開xml文件
5、死鎖信息數據大致如下,仔細閱讀,總結即可學會如何從根本上解決死鎖
<deadlock-list>
<deadlock victim="process21e48def088">
<process-list>
<process id="process21e48def088" taskpriority="0" logused="256" waitresource="KEY: 10:72057594043301888 (8194443284a0)" waittime="2947" ownerId="856488786" transactionname="user_transaction" lasttranstarted="2019-05-28T16:32:40.950" XDES="0x21f3d3c0490" lockMode="S" schedulerid="6" kpid="7172" status="suspended" spid="76" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2019-05-28T16:32:44.607" lastbatchcompleted="2019-05-28T16:32:44.603" lastattention="1900-01-01T00:00:00.603" clientapp="Microsoft SQL Server Management Studio - 查詢" hostname="CNSPDHLOTTRACE" hostpid="7660" loginname="developer" isolationlevel="read committed (2)" xactid="856488786" currentdb="10" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
<executionStack>
<frame procname="adhoc" line="4" stmtstart="24" stmtend="96" sqlhandle="0x0200000058b29a123afc09554bf56fb624ca094e650c3a150000000000000000000000000000000000000000">
unknown
</frame>
<frame procname="adhoc" line="4" stmtstart="70" stmtend="132" sqlhandle="0x020000009257d20772bd2e19d62ba8f2cfba59c406b7df5a0000000000000000000000000000000000000000">
unknown
</frame>
</executionStack>
<inputbuf>
--session3 3 3 3 3 3 3 3 3 3
SELECT * FROM Test_DL WHERE ID=1
</inputbuf>
</process>
<process id="process21f39bbb468" taskpriority="0" logused="256" waitresource="KEY: 10:72057594043301888 (61a06abd401c)" waittime="4583" ownerId="856387716" transactionname="user_transaction" lasttranstarted="2019-05-28T16:19:14.893" XDES="0x21f201cc490" lockMode="S" schedulerid="5" kpid="2936" status="suspended" spid="71" sbid="0" ecid="0" priority="0" trancount="5" lastbatchstarted="2019-05-28T16:32:42.973" lastbatchcompleted="2019-05-28T16:32:42.970" lastattention="2019-05-28T16:17:39.603" clientapp="Microsoft SQL Server Management Studio - 查詢" hostname="CNSPDHLOTTRACE" hostpid="7660" loginname="developer" isolationlevel="read committed (2)" xactid="856387716" currentdb="10" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
<executionStack>
<frame procname="adhoc" line="5" stmtstart="24" stmtend="96" sqlhandle="0x0200000058b29a123afc09554bf56fb624ca094e650c3a150000000000000000000000000000000000000000">
unknown
</frame>
<frame procname="adhoc" line="5" stmtstart="78" stmtend="140" sqlhandle="0x02000000933188389d9131c5b0627d866347a1d71fc2455e0000000000000000000000000000000000000000">
unknown
</frame>
</executionStack>
<inputbuf>
--session2 2 2 2 2 2 2 2 2 2
SELECT * FROM Test_DL WHERE ID=2
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594043301888" dbid="10" objectname="deadlockd.dbo.Test_DL" indexname="PK__Test_DL__3213E83F6EC1632C" id="lock21db37f0b80" mode="X" associatedObjectId="72057594043301888">
<owner-list>
<owner id="process21f39bbb468" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process21e48def088" mode="S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594043301888" dbid="10" objectname="deadlockd.dbo.Test_DL" indexname="PK__Test_DL__3213E83F6EC1632C" id="lock21f3db3f800" mode="X" associatedObjectId="72057594043301888">
<owner-list>
<owner id="process21e48def088" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process21f39bbb468" mode="S" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>