MYSQL: ein reconnect nach "Server is gone away" durchführen

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von hubblec4 »

Michl hat geschrieben:@hubblec4: Was hat Du denn für eine Action in Deiner TSQLTransaction stehen?! Konsequenterweise müsste man das tatsächlich für alle Actions fortführen.
....


In der SQLTransaction Komponente die ich auf die Form gezogen hatte stand erst caRollback drinne hatte das dann auf caNone geändert.

In meiner Testversion mit meinem Workaround hatte ich die SQL-Komponeten ja zur laufzeit erzeugt und dort hatte ich nichts bei der Action geändert, denke mal das dann der standardwert caRollback drinne stehen müsste.

Eine sache die noch unterschiedlich ist, wo ich aber nicht weis ob es von entscheidenter wichtigkeit ist, ist folgendes.

Du verwendest eine TMySQL56Connection, ich verwende aber den TSQLConnector(4. Symbol von links). Da ich ein anders Programm geschrieben hatte wo man im Vorfeld die verwendete MySQL version eintragen kann und diese dann im TSQLConnector eingetragen wird(und die entsprechende mysql.dll geladen wird).

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von hubblec4 »

@Michl

Ich habe eben mal deine neuen SQL-Prozeduren so übernommen, bei SQLTransaction die Action auf caRollback gesetzt, dennoch bekomme ich den "gone away error".

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

@mse: "FTrans = Nil" kommt von "TSQLTransaction.StartTransaction;". Frage ich nochmals vor "Opentrans" ab, ob FTrans = Nil ist, dann braucht es die "Assigned"-Abfragen nicht mehr. Allerdings werden bei "Db.StartdbTransaction" die Parameter "(FTrans,FParams.CommaText)" bei MySQL überhaupt nicht benötigt, um OpenTrans auszuführen. Bin mir nicht sicher, was nun das korrekte Vorgehen ist "Assigned" bei Rollback etc. abfragen bzw. OpenTrans bei FTrans=Nil nicht zulassen. Mein Bauchgefühl sagt zweiteres, bin aber auch nicht so im Stoff, dass ich das für alle Transactions aller Datenbanken veraussagen bzw. testen kann. Werde mal beide Patches in den Bugtracker hochladen und meinen Kenntnisstand mitteilen...

Code: Alles auswählen

procedure TSQLTransaction.StartTransaction;
 
var db : TSQLConnection;
 
begin
  if Active then
    DatabaseError(SErrTransAlreadyActive);
 
  db := SQLConnection;
 
  if Db = nil then
    DatabaseError(SErrDatabasenAssigned);
 
  if not Db.Connected then
    Db.Open;
  if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
 
  if FTrans <> nil then  //Abfrage hier und alles ist gut
    if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
end;


@hubblec4: Nicht dass wir aneinander vorbeireden, dass die Exception bei einer unterbrochenen Verbindung geworfen wird ist vollkommen i.O. Mit dem Patch bzw. mit den Änderung sollte aber reconnect möglich sein!

Falls das nicht geht, hat das eigentlich mit dem Hack funktioniert?!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von hubblec4 »

Michl hat geschrieben:
@hubblec4: Nicht dass wir aneinander vorbeireden, dass die Exception bei einer unterbrochenen Verbindung geworfen wird ist vollkommen i.O. Mit dem Patch bzw. mit den Änderung sollte aber reconnect möglich sein!

Falls das nicht geht, hat das eigentlich mit dem Hack funktioniert?!



Nein wir reden nicht aneinander vorbei. Die Exeption wird in jedem fall ausgelöst da ja die alte verbindung weg ist.
Es geht um den reconnect wo sich mein SQL.Connector nicht auf false setzen lässt.

deinen "häßlichen hack" habe ich eben mal probiert. Es hat soweit funktioniert das sich der SQL.Connector auf false setzen lies und ein direktes abfragen der DB innerhalb der reconnect prozedure hat funktioniert. es wird keine neue Exception ausgelösst.

Am freitag kann ich einen ersten rechner dort erneuern. Ich werde dann schauen wie es sich mit diesem rechner verhält, und notfalls drauf drängen das ich das ganze netzwerk dort mal neu machen kann.
Zur not komme ich mit meinem Workaround über die runden bis das Lazarus Team das angepasst hat.

Ich probiere aber gern noch andere sachen aus wenn du was besseres hast.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von mse »

@Michl:
In MSEgui sieht es ähnlich aus:

Code: Alles auswählen

 
procedure TSQLTransaction.StartTransaction;
var
 db: tcustomsqlconnection;
 int1: integer;
begin
 if Active then begin
  DatabaseError(SErrTransAlreadyActive);
 end;
 db:= tcustomsqlconnection(database);
 if Db = nil then begin
  DatabaseError(SErrDatabasenAssigned);
 end;
 inc(fstartcount);
 int1:= fstartcount;
 if checkcanevent(self,tmethod(fonbeforestart)) then begin
  fonbeforestart(self);
 end;
 if not Db.Connected then begin
  Db.Open;
 end;
 if (int1 <> fstartcount) or not db.connected then begin
  exit;
 end;
 if not assigned(FTrans) then begin
  FTrans:= Db.AllocateTransactionHandle;
 end;
 if (tao_fake in foptions) or
                 Db.StartdbTransaction(FTrans,FParams) then begin
  OpenTrans;
 end;
 if checkcanevent(self,tmethod(fonafterstart)) then begin
  fonafterstart(self);
 end;
end;
 

Für MySQL ist Ftrans immer nil, fixes_2_6/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc:

Code: Alles auswählen

 
function TConnectionName.AllocateTransactionHandle: TSQLHandle;
begin
//  Result:=TTransactionName.Create;
  Result := nil;
end;
 

und darf daher im MySQL code nirgends verwendet werden. Das heisst, ob FTrans nil ist oder nicht hängt von der Datenbank ab und sollte nicht für Entscheidungen herangezogen werden.

Code: Alles auswählen

 
procedure TSQLTransaction.StartTransaction;
[...]
  if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
 
  if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans; <<<---
 

Obenstehendes funktioniert, da FTrans in MySQL StartdbTransaction() nicht verwendet wird.
fixes_2_6/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc:

Code: Alles auswählen

 
function TConnectionName.StartdbTransaction(trans: TSQLHandle; AParams : string): boolean;
begin
  Result := mysql_query(FMySQL, 'START TRANSACTION') = 0;
  if not Result then
    MySQLError(FMySQL, SErrExecuting, Self);
end;
 

In MSEgui habe ich eine neue einheitliche tmysqlconnection für alle MySQL Versionen ab 5.0 gemacht. Dort sieht es so aus:

Code: Alles auswählen

 
function tmysqlconnection.AllocateTransactionHandle: TSQLHandle;
begin
//  Result:=tmysqltransaction.Create;
 Result:= tmysqltrans.create;
end;
 
function tmysqlconnection.StartdbTransaction(const trans: TSQLHandle;
              const AParams: tstringlist): boolean;
begin
 with tmysqltrans(trans) do begin
  if fconn = nil then begin
   if not ftransactionconnectionused then begin
    fconn:= self.fmysql1;
    ftransactionconnectionused:= true;
   end
   else begin
    openconnection(fconn);
   end
  end;
  begintrans(fconn,aparams.text);
 end;
 result:= true;
end;
 
procedure tmysqlconnection.begintrans(const aconnection: pmysql;
                         const aparams: ansistring);
var
 str1: ansistring;
begin
 str1:= 'START TRANSACTION '+aparams;
 if mysql_real_query(aconnection,pointer(str1),length(str1)) <> 0 then begin
  checkerror(serrstarttransaction,aconnection);
 end;
end;
 

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

mse hat geschrieben:Für MySQL ist Ftrans immer nil...und darf daher im MySQL code nirgends verwendet werden. Das heisst, ob FTrans nil ist oder nicht hängt von der Datenbank ab und sollte nicht für Entscheidungen herangezogen werden.
Danke für die Aufklärung, dass FTrans für MySQL auf Nil gesetzt wird, hatte ich gesehen. Mit dem Test

Code: Alles auswählen

  if (FTrans <> nil) and Db.StartdbTransaction(FTrans,FParams.CommaText) then
    OpenTrans;   
würde somit nie für MySQL eine Transaction gestartet. Also bliebe nur der Test bei Rollback etc.

hubblec4 hat geschrieben:Nein wir reden nicht aneinander vorbei. Die Exeption wird in jedem fall ausgelöst da ja die alte verbindung weg ist.
Es geht um den reconnect wo sich mein SQL.Connector nicht auf false setzen lässt.
Sorry, da kann ich Dir leider nicht weiter helfen, da ich nur den Fehler, der bei mir auftaucht debuggen kann. Dieser ist aber bei FPC 2.6.4 und FPC 2.7.1 mit dem 2. Patch bei mir nicht mehr da. Kannst ja, wenn Du Lust hast, das von mir hochgeladene Projekt ja mal testen, ob Du analog trennst und wieder verbindest, wie ich das getestet habe (ist aber nur für den Test zusammengschustert): http://forum.lazarus.freepascal.org/index.php/topic,25208.msg153012.html?PHPSESSID=d3e184daad489fb1b86460d97812d16e#msg153012

hubblec4 hat geschrieben:Ich probiere aber gern noch andere sachen aus wenn du was besseres hast.
Ich nutze, wie hde Dir auch schon den Tipp gegeben hat, zumeist sehr zufrieden Zeos. Scheinbar ist für ein Reconnect die aktuelle Trunc-Version am stabilsten?! Diese kannst Du Dir per SVN von hier holen:http://svn.code.sf.net/p/zeoslib/code-0/branches/testing-7.2/

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von hubblec4 »

@Michl

so richtig testen konnte ich dein kleines MySQL tool nicht. ich habe nur MySQL5.5 installt.

wenn ich das projekt öffne sehe ich auch keine Form und kann die Komponenten nicht ändern, denke mal liegt an der unterschiedlichen Lazarus version.

Da aber dein "häßlicher hack" und mein workaround ihre arbeit tun, denke ich mal kann ich warten bis das Lazarusteam da was entsprechendes umgebaut hat.
Du hast es im Bugtracker ja auch sehr schön eingerichtet. Hat sich denn da schon mal einer bei dir gemeldet zwecks diesem bug?

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

Ist zwar egal, wenn Du erstmal arbeiten kannst. Ich hatte (hoffentlich verständlich) im englischen Post dazugeschrieben, dass man die Connection entsprechend entfernen und die Connection für MySQL5.5 auf Formular platzieren (mit dem Namen "Connection"), alles weitere wäre dann zur Laufzeit angepasst wurden. Das Formular kannst Du unter Project -> Formulare -> Form1 Dir anzeigen lassen (Units analog). Musst Du aber nicht testen, ist auch nur zum testen für mich gewesen.

hubblec4 hat geschrieben:Hat sich denn da schon mal einer bei dir gemeldet zwecks diesem bug?
Da wird sich niemand bei mir melden, weiss auch nicht, wer per FPC für SQLdb zuständig ist und wie (die-)derjenige Zeit hat. Mal geht die Bearbeitung von Bugs innerhalb weniger Stunden, mal tut sich jahrelang nichts. Der Bug ist erstmal gemeldet, ein möglicher Patch/Workaround auch, falls andere darüber stolpern, können Sie diesen evtl. nutzen, ausbauen oder eine Alternativlösung posten. Ich werd da auch nicht länger bohren, da ich weder MySQL noch SQLdb großartig einsetze (bin mit PostgreSQL + SQLite3 und Zeos sehr zufrieden).
PS: Das ist auch das Tolle an Lazarus/Freepascal (und auch Zeos), da man die Sourcen hat, kann man selbst Hand anlegen und ist nicht auf Gedeih und Verderb auf die hoffentlich ordentliche Arbeit Anderer angewiesen!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von mse »

hubblec4 hat geschrieben:Da aber dein "häßlicher hack" und mein workaround ihre arbeit tun, denke ich mal kann ich warten bis das Lazarusteam da was entsprechendes umgebaut hat.

Wenn ich den code richtig lese werden mit dem patch bei MySQL Transaktionen unterdrückt.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

mse hat geschrieben:Wenn ich den code richtig lese sind mit dem patch bei MySQL Transaktionen unterdrückt.
Ja, bei dem Patch3:
Michl hat geschrieben:Mit dem Test

Code: Alles auswählen

if (FTrans <> nil) and Db.StartdbTransaction(FTrans,FParams.CommaText) then
OpenTrans;

würde somit nie für MySQL eine Transaction gestartet

Patch2 sollte aber funktionieren, da je nach Transaction.Action nur Rollback bzw. Commit bei einer ungültigen FTrans unterbunden werden (notwendig bei nicht vorhandener Verbindung beim z.B. Schließen einer Connection).

Bugeintrag hatte ich gestern entsprechend angepasst.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von mse »

FTrans ist AFAIK bei FPC MySQL immer ungültig.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

Arrgh ... verstehe, damit wäre ein Rollback oder Commit selbst bei einer gültigen Verbindung nicht möglich, soweit hatte ich das gar nicht getestet. Danke fürs mitdenken!

Das Problem ist, dass die Connection bei z.B.

Code: Alles auswählen

procedure TSQLTransaction.Rollback;
begin
  if Active then
    begin
    CloseDataSets;
    If LogEvent(detRollback) then
      Log(detRollback,SRollingBack);
    if SQLConnection.RollBack(FTrans) then  //hier
      begin
      CloseTrans;
      FreeAndNil(FTrans);
      end;
    end;
end;
nicht mehr gültig ist.

Dass SQLConnection.RollBack nicht mehr aufgerufen wird ist zwar richtig, das kann ich aber nicht über die Abfrage FTrans=Nil machen, sondern man müsste auf sowas wie SQLConnection=valid testen (Assigned(SQLConnection) bzw. SQLConnection.Connected funktionieren z.B. nicht). Hast Du eine Idee? Werde später nochmal ein bischen Code wälzen, evtl. finde ich noch einen Ansatz, wenn Du ihn nicht auf Anhieb weißt :wink: ?!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von mse »

Vielleicht wie bei MSEgui, ein try-except in TDataBase.CloseTransactions() und ein try-finally in TSQLTransaction.Rollback().
Ich vermute du findest den MSEgui code. ;-)

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von Michl »

:) Ja, den finde ich bzw. habe ich gefunden und erfolgreich umgesetzt. Ein Reconnect ist möglich und ein Update auch (logischerweise nicht im Debugmodus):

Code: Alles auswählen

Unit SQLdb
...
procedure TSQLTransaction.Rollback;
begin
  if Active then
    begin
      CloseDataSets;
      If LogEvent(detRollback) then
        Log(detRollback,SRollingBack);
      try
        SQLConnection.RollBack(FTrans);
      finally
        CloseTrans;
        FreeAndNil(FTrans);
      end;
    end;
end;
und

Code: Alles auswählen

database.inc
...
procedure TDatabase.CloseTransactions;
var
  I: Longint;
begin
  If Assigned(FTransactions) then begin
    For I:=FTransactions.Count-1 downto 0 do begin
      try
        TDBTransaction(FTransactions[i]).EndTransaction;
      except
      end;
//      TDBTransaction(FTransactions[i]).FinalizeTransaction;  //was machst Du hier?
    end;
  end;
end;
Ich muss jetzt weg, werde aber versuchen einen erneuten, hoffentlich letzten, Patch mit allen Änderungen heute abend zu erstellen - vielen Dank Dir! (PS: müsstest mich mal mit ein bischen mehr mit Nachdruck auf die richtige Spur führen, damit ich nicht so lange auf dem Holzpfad wandel :wink: )

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: MYSQL: ein reconnect nach "Server is gone away" durchfüh

Beitrag von hubblec4 »

@Michl

von meiner seite her hast du schon mal allen dank und respekt. ohne dich wäre ich nichtmal auf meinen eigenen workaround gekommen.

wenn du die anpassungen erneuert hast teste ich diese auch gerne wieder.

Ich werde aber deinen Hack vorerst verwenden.

Code: Alles auswählen

type
 
  { THackTransaction }
 
  THackTransaction = Class(TSQLTransaction)
    public
      procedure CloseTrans;
  end;
...
procedure THackTransaction.CloseTrans;
begin
  inherited CloseTrans;
end;
...
procedure TForm1.Button2Click(Sender: TObject);
begin
  try
    MySQL56Connection1.Connected:=False;
    MySQL56Connection1.Connected:=True;
    Open;
  except
    on e: exception do begin
      ShowMessage('TForm1.Button2Click.Fehler: '+e.Message);
      Reconnect;
      Open;
    end;
  end;
end;
 
procedure TForm1.Reconnect;
begin
  try
    THackTransaction(SQLTransaction1).CloseTrans;
    MySQL56Connection1.Connected:=False;
    MySQL56Connection1.Connected:=True;
  except
    on e: exception do
      ShowMessage('TForm1.Reconnect.Fehler: '+e.Message);
  end;
end;


Der funtionierte gut und ich muss da vorerst nix in der SQLdb ändern.

Ihr redet hier ab und zu von Zeos: wo finde ich das in Lazarus oder muss ich da irgendwas nachinstallieren?

Antworten