2013-07-24 125 views
1

我在2个访问MySQL数据库的应用程序中使用UniDAC(Devart)。 在某个应用程序进行的某些繁重的更新更新操作中,偶尔会出现错误“尝试获取锁定时发现的#40001死锁;尝试重新启动事务”。在阅读MySQL提示以应对这种情况后,他们说要重试交易。我的问题是要知道在Delphi中做到这一点的最佳方式。我这样做:避免死锁MySQL/UniDAC/Delphi

transaction_completed_ok:= False; 
repeat 
    try 
    my_db.StartTransaction; 
    (... do the inserts) 
    my_db.Commit; 
    transaction_completed_ok:= True; 
    except 
    my_db.Rollback; 
    Sleep(1000); 
    end; 
until transaction_completed_ok; 

这样做每一笔交易,在两个应用程序,是处理问题的一个有效方法是什么?任何人都可以分享最佳方式吗?欢迎任何帮助。

+1

不需要'Sleep()',因为锁已经被竞争事务获得,因此立即重试这个锁将导致它等待获取锁而不是死锁。此外,您可能想检查事务失败的原因,因为您可能希望以不同的方式处理死锁以外的其他情况。 – eggyal

回答

2

您的错误重新启动事务代码无法解决问题,因为重新执行一个相同的代码会导致相同的错误。例如,如果您的代码导致违反唯一性,那么应用程序将会卡住。为了解决这个问题,你应该重新组织应用逻辑,以避免死锁。

connection1 locks tableA; 
connection2 locks tableB; 
connection1 attempts to lock tableB - waits for connection2 to unlock tableB; 
connection2 attempts to lock tableA - waits for connection1 to unlock tableA. 

作为结果,我们得到了一个死锁:当两个并联连接试图锁定以不同的顺序2个表,例如发生 死锁。为了避免死锁,您应该设置相同的表锁定为了让这两个连接,例如:

connection1 locks tableA; 
connection2 locks tableA; 
connection1 locks tableB; 
connection2 locks tableB. 

您可以在http://dev.mysql.com/doc/refman/5.1/en/innodb-deadlocks.html

阅读有关死锁的更多信息,为了解决这个问题,你可以使用下面的算法:

+0

如果您在2个不同的应用程序中使用2个不同的连接,这不会解决,除非您让它们之间进行通信。 –