查数据库死锁的实际例子

一个项目上的数据库宕掉了,开始非说是我的工作流造成的。我也不是数据库的专家,只能硬着头皮边学边用的查了,怀疑是数据库死锁,就沿着这个方向前进。

首先sa登录查询分析器,执行Dbcc traceon(1204, 3605, -1),其中参数1204代表返回参与死锁的锁的类型以及当前受影响的命令,3605代表trace到的信息必须记录到日志中,-1代表返回当前所有打开的跟踪标记的状态。有几点要注意,1、事件探查器是跟不出死锁的sql的,因为它只是记录执行过的sql,而这些在事务里面死锁的sql都会被回滚的;2、只有在打开这些标记后数据库才会记录日志,打开这些标记会影响数据库性能,记得用完了使用Dbcc traceoff(标记号)关掉。

接着就是再现这个死锁了,让实施人员在远程找5、6个人同时点这个功能,嘿嘿,不错,一下子就出来了。将数据库日志发过来,一般在Program Files\Microsoft SQL Server\MSSQL.4\MSSQL\LOG\ERRORLOG下。打开文件仔细看发现下面的日志。

2008-05-31 10:10:46.20 spid5s      Node:1

2008-05-31 10:10:46.20 spid5s      RID: 5:1:6815:21               CleanCnt:3 Mode:X Flags: 0x2
2008-05-31 10:10:46.20 spid5s       Grant List 2:
2008-05-31 10:10:46.20 spid5s         Owner:0x3711E420 Mode: X        Flg:0x0 Ref:1 Life:02000000 SPID:59 ECID:0 XactLockInfo: 0x387A26FC
2008-05-31 10:10:46.20 spid5s         SPID: 59 ECID: 0 Statement Type: DELETE Line #: 133
2008-05-31 10:10:46.20 spid5s         Input Buf: RPC Event: Proc [Database Id = 5 Object Id = 1254295528]
2008-05-31 10:10:46.20 spid5s       Requested By:
2008-05-31 10:10:46.20 spid5s         ResType:LockOwner Stype:'OR'Xdes:0x533EBC80 Mode: S SPID:67 BatchID:0 ECID:0 TaskProxy:(0x1F092374) Value:0x2962ae40 Cost:(0/0)
2008-05-31 10:10:46.20 spid5s     
2008-05-31 10:10:46.20 spid5s      Node:2

2008-05-31 10:10:46.20 spid5s      KEY: 5:72057594056212480 (fc0199b9be7a) CleanCnt:2 Mode:S Flags: 0x0
2008-05-31 10:10:46.20 spid5s       Grant List 2:
2008-05-31 10:10:46.20 spid5s         Owner:0x2028AD80 Mode: S        Flg:0x0 Ref:1 Life:00000000 SPID:67 ECID:0 XactLockInfo: 0x533EBCA4
2008-05-31 10:10:46.20 spid5s         SPID: 67 ECID: 0 Statement Type: SELECT Line #: 1
2008-05-31 10:10:46.20 spid5s         Input Buf: RPC Event: Proc [Database Id = 5 Object Id = 484053356]
2008-05-31 10:10:46.20 spid5s       Requested By:
2008-05-31 10:10:46.20 spid5s         ResType:LockOwner Stype:'OR'Xdes:0x387A26D8 Mode: X SPID:59 BatchID:0 ECID:0 TaskProxy:(0x576FE374) Value:0x1eb9ad20 Cost:(0/84)
2008-05-31 10:10:46.20 spid5s     
2008-05-31 10:10:46.20 spid5s      Victim Resource Owner:
2008-05-31 10:10:46.20 spid5s       ResType:LockOwner Stype:'OR'Xdes:0x533EBC80 Mode: S SPID:67 BatchID:0 ECID:0 TaskProxy:(0x1F092374) Value:0x2962ae40 Cost:(0/0)

Node1(SPID:59)拥有了一个资源的排他锁Mode: X ,而需要申请另一个资源的共享锁Mode: S,Node2(SPID:67)拥有了后一个资源的共享锁,请求前一个资源的排他锁。根据学校里的零星知识,还是能明白这个道理的。照理说这种情况是不会死锁的,但是如果在事务里,共享锁也会在事务结束以后才释放。

联机丛书上有一些信息可以利用来看这段日志。

类型列

"类型"列显示当前锁定的资源类型。

资源类型
描述

RID
用于锁定表中的一行的行标识符。

KEY
索引中的行锁。用于保护可串行事务中的键范围。

PAG
数据或索引页。

EXT
相邻的八个数据页或索引页构成的一组。

TAB
包括所有数据和索引在内的整个表。

DB
数据库。

资源列

"资源"列提供有关正被锁定资源的信息。

资源类型
描述

RID
表内已锁定行的行标识符。行由 fileid:page:rid 组合进行标识,其中,rid 是页中的行标识符。

KEY
SQL Server 内部使用的十六进制数字。

PAG
页码。页由 fileid:page 组合进行标识,其中,fileid 是 sysfiles 表中的 fileid,而 page 是该文件内的逻辑页码。

EXT
正被锁定的扩展盘区中的第一个页码。页由 fileid:page 组合进行标识。

TAB
由于 ObjId 列已包含表的对象 ID,所以没有提供任何信息。

DB
由于 dbid 列已包含数据库的数据库 ID,所以没有提供任何信息。

sp_lock 的结果集内,锁定的 RID 资源类型中的资源描述为 1:1225:2。这表明在 fileid 1 内、页码为 1225 的页中、行标识符为 2 的行上应用了锁。

最关键的信息我认为是

[Database Id = 5 Object Id = 1254295528]和[Database Id = 5 Object Id = 484053356]
指明了加锁的两个对象。

select  db_name(5)  结果为 cwbase_zclzj
连接 cwbase_zclzj帐套,
select object_name(484053356)  结果为  : erp_LS_BillCodeRule_GenerateNewBillCode
select object_name(1254295528)  结果为: erp_LS_BillFlowNoRecords_NewRecordSave

原来是两个存储过程搞得鬼,在生成单据编号的时候出现了死锁,因为两者是放在同一个事物中,也就验证了我们上面的猜想。简单的处理办法是不要放到同一个事物中,其他的办法就让负责维护的同事去管吧。

就写到这里,其实日志里面的大部分咚咚还是看不懂,等待高人给予解释。如果分析中有什么不对的,也请各位回复指出,我也进一步学习一下。谢谢!

转载于:https://www.cnblogs.com/ipointer/archive/2008/06/05/1214005.html

<think>好的,我现在需要处理用户关于数据库死锁的问题。用户已经提供了三个引用链接,我需要结合这些资料来回答如何诊断和解决数据库死锁的问题。首先,我得理解什么是数据库死锁。根据引用[1],死锁是指两个或多个事务相互等待对方释放资源,导致系统无法继续执行。接下来,用户需要的是具体的诊断和解决方法。 首先,诊断死锁的步骤。引用[3]提到了如何判断死锁,可能包括数据库日志或使用工具检测。例如,MySQL的SHOW ENGINE INNODB STATUS命令可以显示最近的死锁信息。另外,数据库管理系统通常有死锁检测机制,自动检测并处理,比如回滚其中一个事务。 然后是解决策略。引用[2]提到锁虽然解决并发问题,但会导致死锁。解决方法可能包括设置超时机制,让事务在等待一定时间后自动回滚。还有死锁预防,比如按照固定顺序访问资源,或者使用乐观锁来减少锁的使用。此外,调整事务的大小和持续时间,减少锁的持有时间,也能有效预防死锁。 还需要考虑实际应用中的例子,比如在订单和库存系统中,按照相同的顺序更新表,避免循环等待。或者使用数据库的锁超时参数,如MySQL的innodb_lock_wait_timeout。 不过,我需要确保这些方法确实来自提供的引用。例如,引用[1]提到预防和解决策略,引用[2]强调死锁的严重性,引用[3]提供了一些外部链接可能有具体检测方法。因此,在回答中要正确引用这些来源,并组织成清晰的步骤,帮助用户逐步诊断和解决死锁问题。 最后,生成相关问题时要围绕死锁的原因、检测工具、预防措施和应用场景,确保问题有针对性,帮助用户进一步理解。</think>### 数据库死锁的诊断与解决方法 #### 一、死锁诊断步骤 1. **监控数据库日志** 大多数数据库系统(如MySQL、Oracle)会自动记录死锁事件。例如,MySQL可通过以下命令看最近的死锁信息: ```sql SHOW ENGINE INNODB STATUS; ``` 日志会包含事务ID、等待资源和冲突操作等关键信息[^3]。 2. **启用死锁检测工具** - 使用数据库内置的监控工具(如SQL Server Profiler、MySQL Workbench的Performance Schema)跟踪锁竞争情况。 - 分析慢询日志,识别长时间未完成的事务[^1]。 3. **识别阻塞链** 通过询系统视图(如`sys.dm_tran_locks` in SQL Server)定位阻塞事务的依赖关系,找到形成循环等待的“死锁图”。 --- #### 二、死锁解决策略 1. **自动处理机制** 数据库系统通常内置死锁检测和回滚机制。例如,InnoDB引擎会自动回滚代价较小的事务以解除死锁[^3]。 2. **手动干预** - **终止事务**:强制终止参与死锁的某个事务(需评估业务影响)。 - **调整隔离级别**:降低隔离级别(如从`SERIALIZABLE`改为`READ COMMITTED`),减少锁竞争[^2]。 3. **优化事务设计** - **固定资源访问顺序**:所有事务按相同顺序访问表和行,避免循环等待。 例如,先更新`订单表`再更新`库存表`,全局统一顺序。 - **缩短事务时间**:减少事务内操作量,避免长时间持有锁。 使用批量操作或拆分大事务为小事务[^2]。 4. **设置锁超时** 为事务配置锁等待超时参数(如MySQL的`innodb_lock_wait_timeout`),超时后自动回滚并重试。 5. **使用乐观锁** 通过版本号或时间戳实现无锁并发控制(如CAS操作),减少显式锁的使用。 --- #### 三、预防措施 1. **索引优化** 为高频询字段添加索引,减少全表扫描导致的锁范围扩大[^1]。 2. **避免热点更新** 分散热点数据(如将计数器拆分为多行),降低并发冲突概率。 3. **定期分析死锁日志** 通过日志分析高频死锁场景,针对性优化表结构或业务逻辑。 --- #### 示例场景 **问题**:订单支付时同时更新用户余额和订单状态,发生死锁。 **解决方案**: 1. 统一先更新用户表,再更新订单表。 2. 为`user_id`和`order_id`添加索引。 3. 使用乐观锁版本字段控制并发更新。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值