1

我在 2 个访问 MySQL 数据库的应用程序中使用 UniDAC (Devart)。在一个应用程序进行一些繁重的更新更新操作期间,有时我会在另一个应用程序中收到错误“#40001 Deadlock found when trying to get lock; try restarting transaction”。在阅读了 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;

对两个应用程序上的每笔交易都这样做是解决问题的有效方法吗?谁能分享一个最好的方法?欢迎任何帮助。

4

1 回答 1

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;
于 2013-07-25T12:51:02.333 回答