我在访问MySQL数据库的2个应用程序中使用UniDAC(Devart)。 在一个应用程序进行的一些繁重的更新更新操作期间,偶尔我会在另一个应用程序中收到错误“#40001在尝试获取锁定时发现死锁;尝试重新启动事务”。在阅读了MySQL提示以应对这种情况之后,他们说要重试交易。我的问题是要知道在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;
对两个应用程序的每个事务执行此操作是处理问题的有效方法吗?任何人都可以分享最佳方式吗?欢迎任何帮助。
答案 0 :(得分:2)
您在错误时重启事务的代码无法解决问题,因为重新执行同一个代码会导致相同的错误。例如,如果您的代码导致唯一性违规,则应用程序将被卡住。要解决此问题,您应该重新组织应用程序逻辑,以避免死锁。 当两个并行连接尝试以不同的顺序锁定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.
结果,我们陷入僵局。要避免死锁,应为两个连接设置相同的表锁定顺序,例如:
connection1 locks tableA;
connection2 locks tableA;
connection1 locks tableB;
connection2 locks tableB.
您可以在http://dev.mysql.com/doc/refman/5.1/en/innodb-deadlocks.html
上阅读有关死锁的更多信息要解决此问题,您可以使用以下算法:
isLocked := False;
while not isLocked do
try
< explicit lock tableA >
< explicit lock tableB >
isLocked := True;
except
< explicit unlock tableA >
< explicit unlock tableB >
end;
if isLocked then
try
< do inserting to tableA and tableB >
finally
< explicit unlock tableA >
< explicit unlock tableB >
end;