Deal with deadlocks in MySQL

Discussion of open issues, suggestions and bugs regarding UniDAC (Universal Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
miguelenguica
Posts: 18
Joined: Mon 11 Apr 2011 15:28

Deal with deadlocks in MySQL

Post by miguelenguica » Wed 24 Jul 2013 20:07

Hi.
During some heavy update update operations made by a separate application, occasionally I get an Error "#40001 Deadlock found when trying to get lock; try restarting transaction". Having read MySQL tips to cope with this is to retry the transaction. My question is to know the best way to do this in Delphi. I'm doing this:

Code: Select all

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;
Doing this to every transaction, on both apps, is a valid way to deal with problem?

Any help is welcome. Thanks.

DemetrionQ
Devart Team
Posts: 271
Joined: Wed 23 Jan 2013 11:21

Re: Deal with deadlocks in MySQL

Post by DemetrionQ » Thu 25 Jul 2013 12:49

Hello.

Your code for restarting transaction on error cannot solve the problem, since re-execution of one and the same code will cause the same errors. For example, if your code causes uniqueness violation, the application will get stuck. To solve the problem, you should reorganize the application logic, in order to avoid a deadlock.
A deadlock occurs when two parallel connections attempt to lock 2 tables in a different order, for example:

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.

As a result, we get a deadlock. To avoid the deadlock, you should set the same table locking order for both connections, for example:

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

You can read more information about deadlock at http://dev.mysql.com/doc/refman/5.1/en/ ... locks.html

To solve the problem, you can use the following algorithm:

Code: Select all

  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;

miguelenguica
Posts: 18
Joined: Mon 11 Apr 2011 15:28

Re: Deal with deadlocks in MySQL

Post by miguelenguica » Thu 25 Jul 2013 14:44

Hi. Thank you for your answer. I understand how to deal with deadlocks inside the same application. The problem is that this happens with two different applications writing to the same database, and sometimes to the same table.

If I check the "innodb_lock_waits" table inside the information_schema db and wait until it's empty to start a new transaction, would this be a valid way to avoid deadlocks completely?

Thanks.

DemetrionQ
Devart Team
Posts: 271
Joined: Wed 23 Jan 2013 11:21

Re: Deal with deadlocks in MySQL

Post by DemetrionQ » Fri 26 Jul 2013 09:19

To avoid a deadlock, you can check if the table is locked before locking it. You can do this using the 'SHOW OPEN TABLES' SQL command ( http://dev.mysql.com/doc/refman/5.1/en/ ... ables.html ), for example:

Code: Select all

SHOW OPEN TABLES WHERE in_use <> 0 AND `Table` = 'YourTable' AND `Database` = 'YourDatabase';

Post Reply