什么是数据库死锁
每个使用关系型数据库的程序都可能遇到数据死锁的情况。理解什么是死锁之前先要了解锁定的概念:如果需要“修改”一条数据,首先数据库管理系统会在上面加锁,以保证在同一时间只有一个事务能进行修改操作。锁定(Locking)发生在当一个事务获得对某一资源的“锁”时,这时,其他的事务就不能更改这个资源了,这种机制的存在是为了保证数据一致性。
多数情况下,可以认为如果一个资源被锁定,它总会在以后某个时间被释放。而死锁发生在当多个进程访问同一数据库时,其中每个进程拥有的锁都是其他进程所需的,由此造成每个进程都无法继续下去。简单的说,进程A等待进程B释放他的资源,B又等待A释放他的资源,这样就互相等待就形成死锁。
一般情况只发生锁超时,就是一个进程需要访问数据库表或者字段的时候,另外一个程序正在执行带锁的访问(比如修改数据),那么这个进程就会等待,当等了很久锁还没有解除的话就会锁超时,报告一个系统错误,拒绝执行相应的SQL操作。
发生死锁的情况比较少,比如一个进程需要访问两个资源(数据库表或者字段),当获取一个资源的时候进程就对它执行锁定,然后等待下一个资源空闲,这时候如果另外一个进程也需要两个资源,而已经获得并锁定了第二个资源,那么就会死锁,因为当前进程锁定第一个资源等待第二个资源,而另外一个进程锁定了第二个资源等待第一个资源,两个进程都永远得不到满足。
use
master
--
必须在master数据库中创建
go
if
exists
(
select
*
from
dbo.sysobjects
where
id
=
object_id
(N
'
[dbo].[p_lockinfo]
'
)
and
OBJECTPROPERTY
(id, N
'
IsProcedure
'
)
=
1
)
drop
procedure
[
dbo
]
.
[
p_lockinfo
]
GO
/**//*
--处理死锁
查看当前进程,或死锁进程,并能自动杀掉死进程
因为是针对死锁的,所以如果有死锁进程,只能查看死锁进程
当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程
感谢: caiyunxia,jiangopen 两位提供的参考信息
--邹建 2004.04(引用请保留此信息)--
*/
/**//*
--调用示例
exec p_lockinfo
--
*/
create
proc
p_lockinfo
@kill_lock_spid
bit
=
1
,
--
是否杀掉死锁的进程,1 杀掉, 0 仅显示
@show_spid_if_nolock
bit
=
1
--
如果没有死锁的进程,是否显示正常进程信息,1 显示,0 不显示
as
set
nocount
on
declare
@count
int
,
@s
nvarchar
(
1000
),
@i
int
select
id
=
identity
(
int
,
1
,
1
),标志,
进程ID
=
spid,线程ID
=
kpid,块进程ID
=
blocked,数据库ID
=
dbid,
数据库名
=
db_name
(dbid),用户ID
=
uid,用户名
=
loginame,累计CPU时间
=
cpu,
登陆时间
=
login_time,打开事务数
=
open_tran, 进程状态
=
status,
工作站名
=
hostname,应用程序名
=
program_name,工作站进程ID
=
hostprocess,
域名
=
nt_domain,网卡地址
=
net_address
into
#t
from
(
select
标志
=
'
死锁的进程
'
,
spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1
=
a.spid,s2
=
0
from
master..sysprocesses a
join
(
select
blocked
from
master..sysprocesses
group
by
blocked
)b
on
a.spid
=
b.blocked
where
a.blocked
=
0
union
all
select
'
|_牺牲品_>
'
,
spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1
=
blocked,s2
=
1
from
master..sysprocesses a
where
blocked
<>
0
)a
order
by
s1,s2
select
@count
=
@@rowcount
,
@i
=
1
if
@count
=
0
and
@show_spid_if_nolock
=
1
begin
insert
#t
select
标志
=
'
正常的进程
'
,
spid,kpid,blocked,dbid,
db_name
(dbid),uid,loginame,cpu,login_time,
open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
from
master..sysprocesses
set
@count
=
@@rowcount
end
if
@count
>
0
begin
create
table
#t1(id
int
identity
(
1
,
1
),a
nvarchar
(
30
),b
Int
,EventInfo
nvarchar
(
255
))
if
@kill_lock_spid
=
1
begin
declare
@spid
varchar
(
10
),
@标志
varchar
(
10
)
while
@i
<=
@count
begin
select
@spid
=
进程ID,
@标志
=
标志
from
#t
where
id
=
@i
insert
#t1
exec
(
'
dbcc inputbuffer(
'
+
@spid
+
'
)
'
)
if
@@rowcount
=
0
insert
#t1(a)
values
(
null
)
if
@标志
=
'
死锁的进程
'
exec
(
'
kill
'
+
@spid
)
set
@i
=
@i
+
1
end
end
else
while
@i
<=
@count
begin
select
@s
=
'
dbcc inputbuffer(
'
+
cast
(进程ID
as
varchar
)
+
'
)
'
from
#t
where
id
=
@i
insert
#t1
exec
(
@s
)
if
@@rowcount
=
0
insert
#t1(a)
values
(
null
)
set
@i
=
@i
+
1
end
select
a.
*
,进程的SQL语句
=
b.EventInfo
from
#t a
join
#t1 b
on
a.id
=
b.id
order
by
进程ID
end
set
nocount
off
go