Page 1 of 1

How to handle deadlock

Posted: 30.05.2012, 09:24
by hstijnen
Hi,
I'm using ZEOS7 in CBuilder XE with MySQL.
When executing a number of consecutive transactions I frequently get a deadlock message: '...raised exception class EZSQLException with message 'SQL Error: Deadlock found when trying to get lock; try restarting transaction'.

I've tried:

Code: Select all

try {
   bool suc = SelectSourceForm->Connection->ExecuteDirect(query, nrec);
}
catch (EZSQLException &exception) {
    .....
}
In case of that deadlock suc is set to false, but the EZSQLException is not catched! Is that to be expected?

What's the best way to handle this situation?

Best Regards,

Henk

Posted: 30.05.2012, 21:31
by EgonHugeist
hstijnen,

It seem's you have allways very spezial issues or faq's to post. :)

I'll take a look to the documentations @weekend. Actually i must admit i don't know what deadlock is.. :oops:

Or can you tell me what that is exactly? Can you give us a code example that raises this exception?

Michael

Posted: 31.05.2012, 15:53
by hstijnen
Hi Michael
I only know roughly what is a deadlock. AFAIK it works as follows. When you update a row in a table, the dbms does the following:
1. put a lock on that row (to prevent simultaneous updates by different processes)
2. update the row
3. removes the lock.
When step 3 fails and another user/process tries to update that record you can get a deadlock.

However, in my case the deadlock appears when I am inserting records in some table, in which case I think nothing is to be locked. So I don't fully apprehend the phenomenon.

In the past I had some like thing. I then used ZQuery->ExecSQL, and it disappeared when using ZConnection->ExecuteDirect. Possibly ZConnection->ExecuteDirect waits for reaction from the server, while ZQuery->ExecSQL does not? But now I'm using ZConnection->ExecuteDirect...

I cannot give a simple code example, for it happens not always at the same time. Likely dependent on database traffic.

So far as I can see in the stack the EZSQLException is raised in CheckMySQLError, but the exception reaches not the calling code of my C++ program.

Here is the code:

Code: Select all

procedure CheckMySQLError(PlainDriver: IZMySQLPlainDriver;
  Handle: PZMySQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string);
var
  ErrorMessage: string;
  ErrorCode: Integer;
begin
  ErrorMessage := Trim(String(StrPas(PlainDriver.GetLastError(Handle))));
  ErrorCode := PlainDriver.GetLastErrorCode(Handle);
  if (ErrorCode <> 0) and (ErrorMessage <> '') then
  begin
    if SilentMySQLError > 0 then
      raise EZMySQLSilentException.CreateFmt(SSQLError1, [ErrorMessage]);

    DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage,
      ErrorCode, ErrorMessage);
    raise EZSQLException.CreateWithCode(ErrorCode,
      Format(SSQLError1, [ErrorMessage]));
  end;
end;

called from:

function TZMySQLStatement.ExecuteUpdate(const SQL: string): Integer;
var
  QueryHandle: PZMySQLResult;
  HasResultset : Boolean;
begin
  Result := -1;
  {$IFDEF DELPHI12_UP}
  if FPlainDriver.ExecQuery(FHandle, PAnsiChar(AnsiString(SQL))) = 0 then
  {$ELSE}
  if FPlainDriver.ExecQuery(FHandle, PAnsiChar(SQL)) = 0 then
  {$ENDIF}
  begin
    DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL);
    HasResultSet := FPlainDriver.ResultSetExists(FHandle);
    { Process queries with result sets }
    if HasResultSet then
    begin
      QueryHandle := FPlainDriver.StoreResult(FHandle);
      if QueryHandle <> nil then
      begin
        Result := FPlainDriver.GetRowCount(QueryHandle);
        FPlainDriver.FreeResult(QueryHandle);
      end
      else
        Result := FPlainDriver.GetAffectedRows(FHandle);
    end
    { Process regular query }
    else
      Result := FPlainDriver.GetAffectedRows(FHandle);
  end
  else
    CheckMySQLError(FPlainDriver, FHandle, lcExecute, SQL);
  LastUpdateCount := Result;
end;

called from:

function TZAbstractConnection.ExecuteDirect(SQL:string; var RowsAffected:integer):boolean;
var
  stmt : IZStatement;
begin
  try
    try
      CheckConnected;
      stmt := DbcConnection.CreateStatement;
      RowsAffected:= stmt.ExecuteUpdate(SQL);
      result := (RowsAffected <> -1);
    except
      RowsAffected := -1;
      result := False;
    end;
  finally
    stmt:=nil;
  end;
end;

called from:

function TZAbstractConnection.ExecuteDirect(SQL : String) : boolean;
var
  dummy : Integer;
begin
  result:= ExecuteDirect(SQL,dummy);
end;

Posted: 02.06.2012, 07:59
by EgonHugeist
Hi Henk,

Slightly i did read me in the deadlock issue. If i understand everything right than it is an issue with InnoDB and i higher transaction level than tiReadCommited.

What makes me wondering is that this error will not be raised, or do i understand you wrong? Now i see that we check for silentMySQLError and SQLError1. Hmm in my mind that could be the reason that the Exception does not reach you app... But i don't know it for sure now. I'll check, where these values are set this evening. I hope well find a solution..

Michael

Posted: 09.10.2012, 16:38
by hstijnen
Hi Michael,
I got again exceptions that I could not catch. Now i've added a line in the Zeos code:
function TZAbstractConnection.ExecuteDirect(SQL:string; var RowsAffected:integer):boolean;
var
stmt : IZStatement;
begin
try
try
CheckConnected;
stmt := DbcConnection.CreateStatement;
RowsAffected:= stmt.ExecuteUpdate(SQL);
result := (RowsAffected <> -1);
except
RowsAffected := -1;
result := False;
raise {------ added by Henk 09-10-2012 --------}
end;
finally
stmt:=nil;
end;
end;

And now I can catch the exception!

Posted: 09.10.2012, 18:30
by EgonHugeist
hstijnen,

patch applied. Rev 1908 \testing.

Thanks Henk.