如何防止插入删除表造成的数据库死锁

         在数据库中经常会遇到这样的情况:一个主表A,一个子表B,B表中包含有A表的主键作为外键。当要插入数据的时候,我们会先插入A表,然后获得A表的Identity,再插入B表。如果要进行删除操作,那么就先删除子表B,然后再删除主表A。在程序设计中,对两个表的操作是在一个事务之中完成的。
当系统使用频繁就会出现插入操作和删除操作同时进行的情况。这个时候插入事务会先将主表A放置独占锁,然后去访问子表B,而同时删除事务会对子表B放置独占锁,然后去访问主表A。插入事务会一直独占着A表,等待访问B表,删除事务也一直独占着B表等待访问A表,于是两个事务相互独占一个表,等待对方释放资源,这样就造成了死锁。
遇到这种情况我听说了三种做法:

1 取消AB两个表之间的外键关系,这样就可以在删除数据的时候就可以先删除主表A,然后删除子表B,让对这两个表操作的事务访问顺序一致。

2 删除A表数据之前,先使用一个事务将B表中相关外键指向另外A表中的另外一个数据(比如在A表中专门建一行数据,主键设置为0,永远不会对这行数据执行删除操作),这样就消除了要被删除的数据在AB两个表中的关系。然后就可以使用删除事务,先删除A表中的数据,再删除B表中的数据,以达到和插入事务表访问一致,避免死锁。

3 在外键关系中,将“删除规则”设置为“层叠”,这样删除事务只需要直接去删除主表A,而不需要对子表B进行操作。因为删除规则设置为层叠以后,删除主表中的数据,子表中所有外键关联的数据也同时删除了。

以上三个解决办法都是同事给出的建议,我也不知道到底该使用什么办法才好。
不知道对于这种情况要防止死锁大家还有没有什么其他好办法?
【出自博客园深蓝居,转载请注明作者出处】
posted @ 2007-06-11 23:19 深蓝 阅读(3411) 评论(28)  编辑 收藏 所属分类: SQL开发

  回复  引用  查看    
#1楼2007-06-11 23:45 | Cat Chen      
方法3中的cascade不正是为此而设计的吗?关系型数据库,当然先要从语义上正确描述集合的关系,而cascade就是用于此语义的。
  回复  引用  查看    
#2楼2007-06-12 07:06 | 丁学      
1不可取,2多了一次更新操作,3还可以
一般插入时不需要使用事务,删除时用cascade
插入时可能出现的数据不完整,在读取时作验证,不完整数据直接忽略,跑作业定期清理。因为无论插入时使用不使用事务,读取时都要作验证以确保数据正确性而不致程序出错,对应的定期数据清理也是必不可少的,所以并不会因为插入时不使用事务而造成过多的数据库访问

  回复  引用    
#3楼2007-06-12 07:14 | laopeng[未注册用户]
@Cat Chen
具体怎么用呢?

  回复  引用  查看    
#4楼2007-06-12 09:15 | Cat Chen      
@laopeng
楼主已经说了啊,外键设置cascade,删除的时候自动会层叠删除,就那么简单。

  回复  引用    
#5楼2007-06-12 09:23 | jameswei[未注册用户]
这样易误删!不可取
  回复  引用  查看    
#6楼2007-06-12 09:37 | OOP      
我所设计的有主外键关系的表,都是设置联动更新和删除的,确保数据的准确性。
  回复  引用    
#7楼2007-06-12 10:10 | 加大码[未注册用户]
@OOP
是通过触发器删除吗?

  回复  引用  查看    
#8楼2007-06-12 10:27 | Klesh Wong      
从理论上看,1和2那还叫“关系模型”吗?
但就从实用方便的角度出发,3不也是最科学方便快捷的方法吗?
唉,就如此问题也分析不出优劣吗?嗟乎……

  回复  引用    
#9楼2007-06-12 11:02 | 阿毅[未注册用户]
用方法3,并规范相关操作的调用,比如通过权限设定限定删除操作不会被随意执行,更大程度上避免误删。
  回复  引用    
#10楼2007-06-12 11:36 | progame[未注册用户]
现在一般数据库都是行级锁或页级锁 没有那么容易独占锁死表的

另外就是越来越多的需求是:即使是删除的数据也要保留在数据库中查看
所以一般我是使用删除标志而不是把数据删除

  回复  引用  查看    
#11楼2007-06-12 11:39 | Cat Chen      
其实遇到这些问题时,建议还是去看看比较系统的关系型数据库的教材吧,掌握了语言设计时背后的语义才能真正把它用好。

这就好像很多人用HTML,完全不管标签的语义,只为追求视觉上达到自己想要的效果,用可视化工具直接设计<table />布局,这其实是错误的。正确的做法应该是去系统学习HTML,理解每一个标签做什么的,以及整个HTML语言能为你做什么,然后按语义去设计页面。

现在你面对的情况也差不多,层叠删除只是一个你需要的表面的功能,就如同Photoshop出的一张网页布局图那样,你当然可以为求结果而寻找解决方案,但这往往不那么好。因此你应该反过来想你的数据到底是描述什么的,寻找正确的scheme来描述你的数据,剩余的事情SQL Server帮你搞定。

  回复  引用  查看    
#12楼2007-06-12 11:48 | 杀手      
我觉得2还可以,1不可取,3有风险
  回复  引用  查看    
#13楼[楼主]2007-06-12 13:21 | 深蓝      
Cat Chen 推荐一下有什么经典的书籍嘛,我看过的书都没有讲这个问题。我个人也认为方法3比较好
  回复  引用  查看    
#14楼2007-06-12 13:58 | 66ccff      
《数据库系统概念》
  回复  引用  查看    
#15楼2007-06-12 14:12 | 阿水      
不是吧,这么麻烦 ,主从表模式
很多MIS 系统里都在用 ,不过说实话
楼主的问题 我还没碰到过,可能是访问的不够频繁??
而且你说的情况 应该不会锁住整个表吧,除非你
手动的 锁了整个表 否则的话一般的锁定 都是
针对行的 不会有楼主说的问题呀???

  回复  引用  查看    
#16楼2007-06-12 14:13 | 阿水      
其实本人认为既然使用
存储过程实现的,我觉得
这个问题 完全可以用存储过程搞定
不需要那么麻烦 我个人判断
方法应该比较简单吧 哈哈哈

  回复  引用    
#17楼2007-06-12 22:13 | jlzhou
设置联动更新和删除,严重影响数据库的性能!我试过的!会很糟糕的!
  回复  引用    
#18楼2007-06-12 22:22 | 加大码[未注册用户]
@jlzhou
我也试过,如果数据量很大的话,删除的速度相当慢!!!

  回复  引用  查看    
#19楼2007-06-13 08:45 | 阿水      
触发器 个人觉得不过不是必须的话 还是不要用了
优化,调试 都很麻烦吧

  回复  引用  查看    
#20楼2007-06-13 11:07 | Artech      
第3种做法是值得推荐的做法,虽然具有一定性能影响,但是从数据的一致性考虑,是最佳的。
  回复  引用    
#21楼2007-06-14 09:20 | 路人甲[未注册用户]
是不是用第三种,就没必要用事务呢啊?
  回复  引用  查看    
#22楼2007-06-14 14:32 | Artech      
@路人甲
当然不是,比如你要删除主表的纪录和相关字表的纪录,有可能子表记录删除了,上出主表的操作却失败。
所以Transaction是必须的。

  回复  引用    
#23楼2007-06-15 09:06 | 路人甲[未注册用户]
@Artech

不用事务,主表删除了,子表外键用cascade也被级联被删除了啊。
你的意思是主表删除失败,子表也会被删除啊?

----
在外键关系中,将“删除规则”设置为“层叠”,这样删除事务只需要直接去删除主表A,而不需要对子表B进行操作。因为删
除规则设置为层叠以后,删除主表中的数据,子表中所有外键关联的数据也同时删除了
-----

楼主的意思是事务+外键cascade

  回复  引用    
#24楼2007-06-15 09:20 | 路人甲[未注册用户]
还是要在事务里写对两张表的删除,只是执行的时候它发现外键cascade ,所以不会去对子表操作?????????
  回复  引用  查看    
#25楼2007-06-19 17:57 | Artech      
@路人甲
我的意思,先对子表进行删除,在对主表进行删除,可以出现子表删除成功,主表删除失败。这样Cascde约束仍然满足。所以Transaction的必须的。当然你的逻辑只对主表进行删除,哪有另当别论。

  回复  引用    
#26楼2007-11-07 09:28 | Danny[未注册用户]
认为这是一个YY的问题来的
理由如下:
1、如果对于数据库有如此频繁的操作,这个问题早已超出技术概念。想像一下股票、银行、电信这种机构的数据量,机构自身早就从管理上想办法解决频繁的数据库操作对性能影响的问题。
2、现在所有的MIS系统和机构都不允许事实删除,而采用逻辑删除。
3、数据库的锁因为资源不同分为行、页、簇、表、库,插入和删除在ORACEL下是行锁,在SYBASE和SQLSERVER下是页锁。全表锁不太可能
4、对于同一条数据库插入和删除,好像不存在这种可能吧
5、删除和插入的时间极短,不会造成死锁,而现在的DBMS都有自身处理死锁的能力

以上理由,看来个问题应是作者自身想出来的,而非在现实存在的。即使存在也仅存在于理论层。不要忽略其他因素对系统的影响。

  回复  引用    
#27楼2009-01-09 17:28 | Idle[未注册用户]
为什么说方法1不可取呢?我们现在的系统就是用方法1在做。。。。
  回复  引用  查看    
#28楼[楼主]2009-01-09 17:36 | 深蓝      
@Idle
我们不应该随便去掉外键应用,我们是做的关系数据库,所以应该使用外键来保证表之间的关系。




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 779811




相关文章:

相关链接:

我要啦免费统计