SQL常见死锁例子及分析
生活随笔
收集整理的這篇文章主要介紹了
SQL常见死锁例子及分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
use XTS
--步驟一=============創建測試表===================================================
--測試表1
if(exists(select 1 from sysobjects where id=OBJECT_ID('testa')))drop table testa
CREATE TABLE testa
(id int primary key,--Id,并標記為主建name varchar(10),--姓名age decimal(26,4),--年齡city varchar(10),--所在城市address varchar(10),--家庭地址remark text --備注
)
--創建非聚集索引
create unique nonclustered index testa_idx1 on testa(name,age) --測試表2
if(exists(select 1 from sysobjects where id=OBJECT_ID('testb')))drop table testb
CREATE TABLE testb
(id int primary key,--Id,并標記為主建name varchar(10),--姓名age decimal(26,4),--年齡city varchar(10),--所在城市address varchar(10),--家庭地址remark text --備注
)--創建非聚集索引
create unique nonclustered index testb_idx1 on testb(name,age) --步驟二===================添加測試數據================================================
insert into testa(id,name,age,city,address)
select 1,'joe',20,'hz','zjwz'insert into testa(id,name,age,city,address)
select 2,'jill',25,'hz','zjhz'insert into testa(id,name,age,city,address)
select 3,'Bob',27,'hz','zjhz'insert into testb(id,name,age,city,address)
select 1,'joe',20,'hz','zjwz'insert into testb(id,name,age,city,address)
select 2,'jill',25,'hz','zjhz'insert into testb(id,name,age,city,address)
select 3,'Bob',27,'hz','zjhz'--添加多一點,是為了查詢效率降低,以便快速得到驗證結果
declare @i int=4
while (@i<1000)
begininsert into testa(id,name,age,city,address)
select @i,@i,27,'xxxx','xxxx'
set @i=@i+1
end--步驟三===================創建測試存儲過程及備用表================================================
IF OBJECT_ID ('p1') IS NOT NULL DROP PROC p1
IF OBJECT_ID ('p2') IS NOT NULL DROP PROC p2
--創建備份表,用于查詢存儲過程的結果存儲
if(exists(select 1 from sysobjects where id=OBJECT_ID('testback')))drop table testback
CREATE TABLE testback
(id int primary key,--Id,并標記為主建name varchar(10),--姓名age decimal(26,4),--年齡city varchar(10),--所在城市address varchar(10)--家庭地址
)if(exists(select 1 from sysobjects where id=OBJECT_ID('testback1')))drop table testback1
CREATE TABLE testback1
(id int primary key,--Id,并標記為主建name varchar(10),--姓名age decimal(26,4),--年齡city varchar(10),--所在城市address varchar(10)--家庭地址
)if(exists(select 1 from sysobjects where id=OBJECT_ID('testback2')))drop table testback2
CREATE TABLE testback2
(id int primary key,--Id,并標記為主建name varchar(10),--姓名age decimal(26,4),--年齡city varchar(10),--所在城市address varchar(10)--家庭地址
)--創建存儲過程p1,更新存儲過程
CREATE PROC p1 ASUPDATE testa SET age = age+1 WHERE id = 1UPDATE testa SET age = age-1 WHERE id = 1
GO--創建存儲過程p2,查詢存儲過程
CREATE PROC p2 AS
truncate table testback
insert into testback(id,name,age,address)
select id,name,age,address from testa where name='joe'
GO---死鎖案例一============兩個事物各占有自己的資源,同時又需要對方的資源==================
--查詢一
begin transaction
update a set address='TT' from testa a where id=1
waitfor delay '00:00:10'
select * from testb where id=1
commit transaction
--查詢二
begin transaction
update a set address='TT' from testb a where id=1
waitfor delay '00:00:10'
select * from testa where id=1
commit transaction--死鎖案例二============書簽查詢引起的死鎖=============================================
--高頻率update
while (1=1) exec p1--高頻率select
while (1=1) exec p2Set statistics profile off
UPDATE testa SET age = age+1 WHERE id = 1
select id,name,age,address from testa where name='joe'--死鎖三================在較高隔離級別的事務中,兩個事務同時執行查詢及更新語句============
--查詢事務一
--需要設置事務隔離級別可重復瀆或加事務保持鎖
SET TRANSACTION ISOLATION LEVEL Repeatable read
while(1=1)
begin
begin transaction
truncate table testback1
insert into testback1(id,name,age,address)
select id,name,age,address from testa where id=1
waitfor delay '00:00:10'
update testa set age=age+1 where id=1
update testa set age=age-1 where id=1
commit transaction
end--查詢事務二
SET TRANSACTION ISOLATION LEVEL Repeatable read
while(1=1)
begin
begin transaction
truncate table testback2
insert into testback2(id,name,age,address)
select id,name,age,address from testa where id=1
waitfor delay '00:00:10'
update testa set age=age+1 where id=1
update testa set age=age-1 where id=1
commit transaction
end--死鎖四===========同一個表當兩個事務都在更新不同的記錄時,即使沒有更新索上的字段,
--也會引起死鎖,因為查詢的字段沒有全部在所建的普通索引上面,所以同樣需要通過聚集索引做全表查詢
--但是聚集索引上的行在同一時間點上被不同事務在擁有,這樣就造成了兩個事務查詢的時候都無法獲取
--全部的資源,即造成了死鎖
--測試數據如下
drop table testx
create table testx(id int primary key,name varchar(10),age int)
create index testx_ind1 on testx(name)
insert into testx(id,name,age)
select '1','袁*','22'
insert into testx(id,name,age)
select '2','程*','20'create table testx1(id int primary key,name varchar(10),age int)
create table testx2(id int primary key,name varchar(10),age int)--查詢一
while(1=1)
begin
begin transaction
update testx set age=age+1 where name='程*'
truncate table testx1
insert into testx1(id,name,age)
select id,name,age from testx where name='程*'
commit transaction
end--查詢二
while(1=1)
begin
begin transaction
update testx set age=age+1 where name='袁*'
truncate table testx2
insert into testx2(id,name,age)
select id,name,age from testx where name='袁*'
commit transaction
end--那你們可能就會有疑問,那我是不是單純更新,不做查詢的時候也會死鎖?因為更新如果也是通過非主鍵字段更新時,也是全表掃描。
--答案:不會,至于為什么不會,我們只能理解數據庫本身在更新和查詢時上鎖的原理不一樣,這個我們也可以做個測試例子。
--查詢一=====事務A更新20秒后結束
begin transaction
update testx set age=40 where name='程*'
waitfor delay '00:00:20'
commit transaction--查詢二======事務B在5秒后結束
begin transaction
update testx set age=40 where name='袁*'
waitfor delay '00:00:05'
commit transaction--查詢三====再分開執行下面兩個查詢
select * from testx where name='袁*'
select * from testx where name='程*'--測試結果:
--當我們依次執行查詢一,再執行查詢二,最后執行查詢三:
--結果就是查詢二5秒后(不需要等待查詢一完成)就執行完成了,而查詢三無論執行那個查詢語句都需要等待20秒后(即必須要等待查詢一完成)才能出來查詢查詢結果
--結論就是更新和查詢時上鎖原理不一樣。--=================隔離級別的演示=============================
DBCC USEROPTIONS
--未提交讀(Read uncommitted)演示
--查詢一
SET TRANSACTION ISOLATION LEVEL Read uncommitted
select * from testa where id=100
begin transaction
update testa set city='newxx' where id=100
waitfor delay '00:00:10'
rollback transaction --查詢二
SET TRANSACTION ISOLATION LEVEL Read uncommitted
select * from testa where id=100--已提交讀(Read committed)也叫不可重復瀆
--查詢一
SET TRANSACTION ISOLATION LEVEL Read committed
select * from testa where id=100
begin transaction
update testa set city='newx' where id=100
waitfor delay '00:00:10'
rollback transaction --查詢二
SET TRANSACTION ISOLATION LEVEL Read committed
select * from testa where id=100--可重復讀(Repeatable read)演示(保證在同一個事務中,瀆取數據不會被其他事務更改)
--查詢一
SET TRANSACTION ISOLATION LEVEL Repeatable read
begin transaction
select * from testa where id=100
waitfor delay '00:00:10'
commit transaction--查詢二
SET TRANSACTION ISOLATION LEVEL Repeatable read
update testa set city='new' where id=100--可序列化演示(事務的最高級別,保證事務的串行執行)
--查詢一
SET TRANSACTION ISOLATION LEVEL Serializable
begin transaction
select * from testa
update testa set city='new' where id=100
waitfor delay '00:00:10'
select * from testa
commit transaction --查詢二
SET TRANSACTION ISOLATION LEVEL Serializable
insert into testa(id,name,age,city,address)
select 4000,'Bobx',27,'hz','zjhz'--創建覆蓋索引
drop index testa_idx1 on testa
create index testa_idx1 on testa(name,age) include(id,address)--設置隔離級別為可重復瀆
SET TRANSACTION ISOLATION LEVEL Repeatable read
DBCC USEROPTIONS --開啟事務隔離的方法
declare @sql varchar(8000)
select @sql = '
ALTER DATABASE ' + DB_NAME() + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
ALTER DATABASE ' + DB_NAME() + ' SET TRANSACTION ISOLATION LEVEL read committed;
ALTER DATABASE ' + DB_NAME() + ' SET MULTI_USER;'
Exec(@sql) --查詢事務隔離
DBCC Useroptions --清除緩存
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
DBCC FREESYSTEMCACHE('ALL') --開啟SQL性能分析
Set statistics profile on--開啟SQL執行時間統計
set statistics time ON --開啟磁盤的讀寫統計
set statistics io on--鎖查詢相關
SELECT request_session_id, resource_type, resource_associated_entity_id,
request_status, request_mode, resource_description
FROM sys.dm_tran_locksselect request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName
from sys.dm_tran_locks where resource_type='OBJECT'sp_lock
sp_who
select * from sys.sysprocesses
dbcc inputbuffer(spid)
總結
以上是生活随笔為你收集整理的SQL常见死锁例子及分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何调整照片大小?还不影响照片清晰度?
- 下一篇: [MySQL]教学管理系统