死鎖

--死鎖 /******************************************************************************************************************************************************
死鎖指兩個以上事務相互阻塞相互等待對方釋放它們的鎖,SQL Server會通過回滾其中一個事務並返回一個錯誤來自已解決阻塞問題,讓其他事務完成它們的工作。

整理人:中国风(Roy)

日期:2008.07.20
*****************************************************************************************************************************************************
*/

set nocount on ;
if object_id('T1') is not null
   
drop table T1
go
create table T1(ID int primary key,Col1 int,Col2 nvarchar(20))
insert T1 select 1,101,'A'
insert T1 select 2,102,'B'
insert T1 select 3,103,'C'
go

if object_id('T2') is not null
   
drop table T2
go
create table T2(ID int primary key,Col1 int,Col2 nvarchar(20))
insert T2 select 1,201,'X'
insert T2 select 2,202,'Y'
insert T2 select 3,203,'Z'


go
生成表數據:
/*
T1:
ID          Col1        Col2
----------- ----------- --------------------
1           101         A
2           101         B
3           101         C

T2:
ID          Col1        Col2
----------- ----------- --------------------
1           201         X
2           201         Y
3           201         Z
*/

防止死鎖:
1、    最少化阻塞。阻塞越少,發生死鎖機會越少
2、    在事務中按順序訪問表(以上例子:死鎖2)
3、    在錯誤處理程式中檢查錯誤1205並在錯誤發生時重新提交事務
4、    在錯誤處理程式中加一個過程將錯誤的詳細寫入日誌
5、    索引的合理使用(以上例子:死鎖1、死鎖3)
當發生死鎖時,事務自動提交,可通過日誌來監視死鎖


死鎖1(索引):
--連接窗口1
--
1步:
begin tran
   
update t1 set col2=col2+'A' where col1=101

--3步:
    select * from t2 where col1=201
commit tran


--連接窗口2

--2步:
begin tran
   
update t2 set col2=col2+'B' where col1=203

--4步:
    select * from t1 where col1=103
commit tran



--連接窗口1:收到死鎖錯誤,連接窗口2得到結果:

/*
訊息 1205,層級 13,狀態 51,行 3
交易 (處理序識別碼 53) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。
*/

--連接窗口2:得到結果

/*
----------- ----------- --------------------
3           103         C
*/

處理方法:
--在t1、t2表的col1條件列建索引
create index IX_t1_col1 on t1(col1)
create index IX_t2_col1 on t2(col1)
go

--連接窗口1
--
1步:
begin tran
   
update t1 set col2=col2+'A' where col1=101

--3步:
select * from t2 with(index=IX_t2_col1)where col1=201    --因表數據少,只能指定索引提示才能確保SQL Server使用索引
commit tran



--連接窗口2

--2步:
begin tran
   
update t2 set col2=col2+'B' where col1=203


--4步:
select * from t1 with(index=IX_t1_col1) where col1=103    --因表數據少,只能指定索引提示才能確保SQL Server使用索引
commit tran



--連接窗口1:
/*

ID          Col1        Col2
----------- ----------- --------------------
1           201         X

(1 個資料列受到影響)

*/
--連接窗口2
/*

ID          Col1        Col2
----------- ----------- --------------------
3           103         C

(1 個資料列受到影響)
*/


死鎖2(訪問表順序):

--連接窗口1:
--
1步:
begin tran
   
update t1 set col1=col1+1 where ID=1

--3步:
select col1 from t2 where ID=1
commit tran



--連接窗口2:
--
2步:
begin tran
   
update t2 set col1=col1+1 where ID=1

--4步
select col1 from t1 where ID=1
commit tran


--連接窗口1:

/*
col1
-----------
201

(1 個資料列受到影響)
*/

--連接窗口2:

/*
col1
-----------
訊息 1205,層級 13,狀態 51,行 1
交易 (處理序識別碼 54) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。
*/

處理方法:

--改變訪問表的順序

--連接窗口1:
--
1步:
begin tran
   
update t1 set col1=col1+1 where ID=1

--3步:
    select col1 from t2 where ID=1
commit tran

--連接窗口2:
--
2步:
begin tran
   
select col1 from t1 where ID=1--會等待連接窗口1提交
--
4步
    update t2 set col1=col1+1 where ID=1
commit tran

死鎖3(單表):

--連接窗口1:

while 1=1
   
update T1 set col1=203-col1 where ID=2

--連接窗口2:
declare @i  nvarchar(20)
while 1=1
   
set @i=(select col2 from T1 with(index=IX_t1_col1)where Col1=102);--因表數據少,只能指定索引提示才能確保SQL Server使用索引

--連接窗口1
/*

訊息 1205,層級 13,狀態 51,行 4
交易 (處理序識別碼 53) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。
*/


處理方法:
1、刪除col1上的非聚集索引,這樣影響SELECT速度,不可取.
   
drop index IX_t1_col1 on t1
2、建一個覆蓋索引
    A、
drop index IX_t1_col1 on t1
    B、
create index IX_t1_col1_col2 on t1(col1,col2)


通過SQL Server Profiler查死鎖信息:

啟動SQL Server Profiler——連接實例——事件選取範圍——顯示所有事件
選擇項:
TSQL——SQL:StmtStarting
Locks——Deadlock graph(這是SQL2005新增事件,生成包含死鎖信息的xml值)
     ——Lock:DeadlockChain 死鎖鏈中的進程產生該事件,可標識死鎖進程的ID並跟蹤操作
     ——Lock:Deadlock 該事件發生了死鎖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
死锁是指两个或多个进程在互斥地请求资源的时候,由于资源被占用而无法继续执行,导致所有进程都被阻塞的情况。在Spring Boot中,死锁可能发生在多线程并发访问共享资源时,例如数据库连接池、缓存、锁等。 在给出解决方案之前,我们需要先排查死锁问题。一种常用的排查死锁问题的方法是使用jstack命令输出线程的堆栈信息。通过查看堆栈信息,我们可以定位到可能引起死锁的代码行,并进行解决修复。 下面是一个示例代码,模拟了一个可能导致死锁的场景: ```java package com.xz.springboottest.day1; public class DeadLock { private static final String ACTION_ONE = "拿起碗"; private static final String ACTION_TWO = "拿起筷子"; public static void main(String[] args) { // 哲学家小明 new Thread(() -> { synchronized (ACTION_ONE) { try { Thread.sleep(1000); synchronized (ACTION_TWO) { System.out.println("小明开始吃饭了。。。。。。"); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); // 哲学家小张 new Thread(() -> { synchronized (ACTION_TWO) { try { Thread.sleep(1000); synchronized (ACTION_ONE) { System.out.println("小张开始吃饭了。。。。。。"); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } ``` 以上代码模拟了哲学家就餐的场景,当只剩下一只碗和一双筷子时,可能出现死锁的问题。 对于解决死锁的方法,可以考虑以下几种方案: 1. 避免循环等待:为了避免死锁,可以规定所有线程在请求资源时按照固定的顺序获取,从而避免循环等待。 2. 加锁顺序:在多个线程同时请求多个资源的情况下,为了避免死锁,可以约定线程必须按照相同的顺序请求资源。 3. 设置超时时间:在获取锁的时候设置超时时间,如果超过一定时间还未获取到锁,可以放弃或者重试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值