一个典型的数据库操作事务死锁分析

简介:

【表A】与【表B】之间有外键约束(具体怎么约束的无所谓,因为外键和事务死锁没有绝对关系)。【表A】=主键表,【表B】=外键表。
公司有几位程序员写的代码总是出现死锁,现在将事务死锁情况重现.

using (事务)
{
    
try {
        
for () // 一个循环
        {
            
if (查询【表A】有该【记录】 == false )//这个查询没有用当前事务的数据库连接,而是新开一个数据库连接查询数据库
            {
                将【记录】插入【表A】;
                插入【表B】;
            }
        }
        事务.提交();
    }
catch {
        事务.回滚();
    }
}

 

4月25日早9:00补充:以上代码逻辑如果放在一个存储过程里面,是没有问题的。但是放在C#中,程序员稍不注意,就很可能出现问题。出现问题的关键地方在“查询【表A】”。C#中,如果查询【表A】和当前的事务不是同一个数据库连接,而是新开一个连接,就会死锁(可以看留言中我的回复)。所以:要么
1,查询【表A】改为使用当前事务的数据库连接(推荐用这种方法)
2,要么按下面的进行代码改造,将事务移到循环体内。
当循环只有1次的时候,上面代码运行没有问题。
一旦循环大于1次的时候,死锁立即出现,运行SQL Server 2005的sp_who_lock,发现死锁的地方正是“查询【表A】”这块。为什么呢?
因为:第1次循环,插入【表A】后,事务将【表A】设置了独占锁,但是第1次循环完后,事务并没有提交,也就没有解开【表A】上的独占锁。因为表A被独占锁了,所以第2次循环时,“查询【表A】”这个操作进行不下去(后面的插入【表A】更是如此),一直在等待事务提交以解开锁,但是事务运行到第2次循环的查询【表A】就死了,循环无法继续进行,也就不能运行到循环外边的事务.提交(),【表A】的独占锁永远没法解开死锁就这样产生了。

既然知道了死锁的原因是因为循环里面没有解开独占锁,所以我们应该把事务.提交()放置在循环内。另外根据事务体的逻辑尽量少的原则,我们把事务的声明移植循环体内,使事务体的代码行数尽量少。代码如下。

 

for () // 一个循环
{
    
bool  有记录 = 查询【表A】有该【记录】; // 将这个查询移出事务是良好的编码习惯,虽然这里不必要
     using (事务)
    {        
        
try {
            
if (有记录 ==false )
            {
                将【记录】插入【表A】;
                插入【表B】;
            }
            事务.提交();
        }
catch {
            事务.回滚();
        }
    }
}

经过以上改造之后,几位程序员写的业务运行正常。

由此总结:
1,在C#等程序代码中使用事务,并在事务内进行查询的时候,特别要小心,确保该查询和事务使用的是同一个数据库连接。防止表被独占死锁。
2,事务体内应尽可能少的逻辑,尽可能少的代码行数。
3,4月25日9:00补充:防止事务死锁最好的方法,还是大家推荐的用存储过程,在存储过程里面使用事务(只不过门槛稍高,手工活儿稍多)


本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/archive/2008/04/24/1167550.html,如需转载请自行联系原作者。

目录
相关文章
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
102 0
|
2天前
|
分布式计算 Java 关系型数据库
|
13天前
|
关系型数据库 MySQL Go
数据库的事务操作
数据库的事务操作
|
13天前
|
SQL 关系型数据库 MySQL
11. 数据库的事务
11. 数据库的事务
|
13天前
|
关系型数据库 MySQL Go
数据库的事务操作 | 青训营
数据库的事务操作 | 青训营
|
13天前
|
存储 搜索推荐 数据库
如何选择合适的矢量数据库:选型指南与案例分析
【4月更文挑战第30天】面对众多矢量数据库,如何选择合适的?本文提供了一份选型指南和案例分析。首先,明确业务需求,如推荐系统、图像检索等场景的不同需求;其次,评估数据量,大型项目需选择支持分布式架构的数据库;再者,关注查询性能、技术成熟度和成本。案例中,电商企业选用Faiss实现高效推荐,而互联网公司则因大规模图像检索选择了Milvus,后者以其扩展性和准确性脱颖而出。选择矢量数据库需综合考虑,结合实际以找到最佳匹配。
|
14天前
|
存储 SQL 关系型数据库
Mysql_数据库事务
Mysql_数据库事务
|
21天前
|
SQL 存储 关系型数据库
数据库开发之事务和索引的详细解析
数据库开发之事务和索引的详细解析
16 0
数据库开发之事务和索引的详细解析
|
24天前
|
SQL Oracle 安全
Oracle数据库中的事务和锁
【4月更文挑战第19天】Oracle数据库的事务和锁是确保数据完整性和并发控制的核心机制。事务遵循ACID原则,保证操作的原子性、一致性、隔离性和持久性。通过COMMIT或ROLLBACK来管理事务更改。锁包括共享锁(读)、排他锁(写)、行级锁和表级锁,用于控制并发访问。自动锁机制在DML操作时生效,防止数据冲突。事务和锁共同维护数据库的稳定和安全。
|
1月前
|
存储 NoSQL 容灾
数据库非功能需求分析
本文探讨了业务研发在技术设计中如何满足非功能需求,重点关注数据库系统的角色。内容涵盖数据库的可用性、可靠性、性能、可修改性、安全性及成本。文章强调了根据业务场景选择合适的数据类型(如关系型、非关系型、内存型、图数据库和时间序列数据库)以及考虑数据容量和增长速度。对于性能需求,讨论了响应时间、吞吐量和并发处理能力。此外,还提到了升级路径、兼容性、备份方案和成本控制(硬件、软件和人力成本)在数据库管理中的重要性。
30 0