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

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

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

Beitrag von Michl »

hubblec4 hat geschrieben:wenn du die anpassungen erneuert hast teste ich diese auch gerne wieder.
Habe es auch nochmal für Lazarus 1.2.4 (FPC 2.6.4) getestet, wenn Du willst kannst Du nochmals probieren:
In "mysql.pp" folgenden Code

Code: Alles auswählen

procedure TSQLTransaction.Commit;
begin
  if active then
    begin
      closedatasets;
      if LogEvent(detCommit) then
        Log(detCommit, SCommitting);
      try
        TSQLConnection(Database).commit(FTrans)
      finally
        closeTrans;
        FreeAndNil(FTrans);
      end;
    end;
end;
...
procedure TSQLTransaction.Rollback;
begin
  if active then
    begin
      closedatasets;
      if LogEvent(detRollback) then
        Log(detRollback, SRollingBack);
      try
        TSQLConnection(Database).RollBack(FTrans)
      finally
        CloseTrans;
        FreeAndNil(FTrans);
      end;
    end;
end;
ersetzen und diese Datei mit <Shift> + <F11> ins Projekt mit aufnehmen, sonst wird sie nicht neu übersetzt!

Unit "db" mit in das Projekt aufnehmen und ebenfalls "database.inc" - müssen ebenfalls neu übersetzt werden!
Folgenden Code in "database.inc" ersetzen:

Code: Alles auswählen

procedure TDatabase.CloseTransactions;
 
Var I : longint;
 
begin
  If Assigned(FTransactions) then
    For I:=FTransactions.Count-1 downto 0 do
      try
        TDBTransaction(FTransactions[i]).EndTransaction;
      except
      end;
end;  
Nun sollte es ohne Hack gehen!
hubblec4 hat geschrieben:Ihr redet hier ab und zu von Zeos: wo finde ich das in Lazarus oder muss ich da irgendwas nachinstallieren?
Michl hat geschrieben: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/
Zeos ist eine Alternative für SQLdb und nicht Bestandteil von Lazarus, sondern muss extra installiert werden - das geht einfach und schnell (runterladen, unter Package -> Package-Datei (.lpk) öffnen... die Datei "...\zeos\packages\lazarus\zcomponent.lpk" öffnen, auf "Komplieren" klicken und auf Nutzung -> Installieren klicken). Schon kannst Du Zeos analog zu SQLdb nutzen. Wenn Du nicht mittels SVN (z.B. mit TortoiseSVN) laden willst, kannst Du auch die letzte stabile Version probieren: http://sourceforge.net/projects/zeoslib/

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 »

Michl hat geschrieben:

Code: Alles auswählen

 
//      TDBTransaction(FTransactions[i]).FinalizeTransaction;  //was machst Du hier?
 

Code: Alles auswählen

 
procedure TSQLTransaction.finalizetransaction;
begin
 if (database <> nil) and (ftrans <> nil) then begin
  tsqlconnection(database).finalizetransaction(ftrans);
 end; 
end;
 
procedure tmysqlconnection.finalizetransaction(const atransaction: tsqlhandle);
begin
 with tmysqltrans(atransaction) do begin
  if (fconn <> fmysql1) then begin
   closeconnection(fconn);
  end;
  fconn:= nil;
 end;
end;
 
Es gibt DB's welche im Gegensatz zu Firebird pro Transaktion eine eigene connection benötigen. finalizetransaction() erledigt die Aufräumarbeiten.

Code: Alles auswählen

 
procedure TSQLTransaction.Commit;
begin
  if active then
    begin
      closedatasets;
      if LogEvent(detCommit) then
        Log(detCommit, SCommitting);
      try
        TSQLConnection(Database).commit(FTrans)
      finally
        closeTrans;
        FreeAndNil(FTrans);
      end;
    end;
end;
 
Ich bin nicht sicher, ob das ideal ist. Damit verliert man wahrscheinlich die Möglichkeit im Falle eines commit-Fehlers das Problem durch das Senden anderer Daten innerhalb der laufenden Transaktion zu beheben. In MSEgui sieht commit() so aus:

Code: Alles auswählen

 
function tsqltransaction.docommit(const retaining: boolean): boolean;
 
 procedure dofinish;
 begin
  if not retaining then begin
   closetrans;
   closedatasets;
  end
  else begin
   if //(fcloselock = 0) and //refresh will not be performed later
       ((tao_refreshdatasets in foptions) {or 
      (sco_emulateretaining in 
              tcustomsqlconnection(database).connoptions)} ) then begin
              //no refresh for emulateretaining 2009-06-16 mse
    refreshdatasets(true,true);
   end;
  end;
 end;
 
var
 bo1: boolean;
begin
 result:= false;
 if not (tao_fake in foptions) then begin
  try
   if retaining then begin
    tcustomsqlconnection(database).commitretaining(FTrans);
   end
   else begin
    tcustomsqlconnection(database).commit(FTrans);
   end;
   savepointevent(spek_committrans,0);
  except
   on e: exception do begin
    bo1:= false;
    if checkcanevent(self,tmethod(foncommiterror)) then begin
     foncommiterror(self,e,bo1);
    end;
    if not bo1 then begin
     if tao_catcherror in foptions then begin
      application.handleexception(self);
      exit;
     end
     else begin
      dofinish;
      raise;
     end;
    end;
   end;
  end;
 end
 else begin
  savepointevent(spek_committrans,0);
 end;
 fsavepointlevel:= -1;
 dofinish;
 result:= true;
end;
 
function TSQLTransaction.Commit(const checksavepoint: boolean = true): boolean;
//var
// bo1: boolean;
begin
 result:= true;
 if active then begin
  if checksavepoint and (fsavepointlevel >= 0) then begin
   pendingaction:= cacommit;
   exit;
  end;
  dobeforestop;
  if checkcanevent(self,tmethod(fonbeforecommit)) then begin
   fonbeforecommit(self);
  end;
  result:= docommit(false);
  if result and checkcanevent(self,tmethod(fonaftercommit)) then begin
   fonaftercommit(self);
  end;
  doafterstop;
 end;
end;
 
 

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

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

Beitrag von Michl »

mse hat geschrieben:Ich bin nicht sicher, ob das ideal ist. Damit verliert man wahrscheinlich die Möglichkeit im Falle eines commit-Fehlers das Problem durch das Senden anderer Daten innerhalb der laufenden Transaktion zu beheben.
Das verstehe ich. Darum habe ich mal alle "Commit"- und "EndTransaction"-Aufrufe angesehen. In keinem Fall ist eine Möglichkeit zur Behebung eines Commit-Fehlers erkennbar bzw. vorgesehen. IMHO sollte der Patch für SQLdb zum derzeitigen Stand keine Nachteile bringen.
mse hat geschrieben:In MSEgui sieht commit() so aus:
:) Da bist Du (mir) ein paar ganze Schrittlängen voraus. Ich kann zwar den Code lesen, aber nur erahnen, was Du an den einzelnen Stellen bezweckst :( . Scheinbar stellst Du sogar mehr Ereignisse Deiner Transaction zur Verfügung als SQLdb und sogar Zeos (z.B. "fonaftercommit")?! Immer wieder: meine Hochachtung hast Du für Dein Projekt!!!

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 »

Michl hat geschrieben:
mse hat geschrieben:Ich bin nicht sicher, ob das ideal ist. Damit verliert man wahrscheinlich die Möglichkeit im Falle eines commit-Fehlers das Problem durch das Senden anderer Daten innerhalb der laufenden Transaktion zu beheben.
Das verstehe ich. Darum habe ich mal alle "Commit"- und "EndTransaction"-Aufrufe angesehen. In keinem Fall ist eine Möglichkeit zur Behebung eines Commit-Fehlers erkennbar bzw. vorgesehen. IMHO sollte der Patch für SQLdb zum derzeitigen Stand keine Nachteile bringen.
Einverstanden.
mse hat geschrieben:In MSEgui sieht commit() so aus:
:) Da bist Du (mir) ein paar ganze Schrittlängen voraus. Ich kann zwar den Code lesen, aber nur erahnen, was Du an den einzelnen Stellen bezweckst
MSEgui unterstützt savepoints, zum Teil sogar vollautomatisch für post()-updaterecord()-Kaskaden durch setzen des dso_postsavepoint flags. Das ist einerseits sehr praktisch für automatische master-detail updates, andererseits schrecklich kompliziert zu Implementieren...

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

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

Beitrag von hubblec4 »

Hallo an die beiden Profis hier.

Nochmals vielen Dank das ihr euch so gut um mein problem gekümmert habt.

Heute werde ich einen der Rechner im Netzwerk erneuern. Denn es tritt dieser Fehler weiterhin auf, und jetzt teilweise an dem Rezeptionsrechner der vorher kaum sorgen gemacht hat.
Der gone away error lässt sich sehr gut abfangen (der Transaction Hack tut also seine arbeit).

Allerdings gibt es noch einen zweiten Fehler "Lost Connection during query"
hierbei scheint es so abzulaufen das die daten noch in die DB geschrieben werden, konnte das aber nicht ausgiebig testen.

Ich werde mich dann wieder melden.

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

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

Beitrag von hde »

hubblec4 hat geschrieben: Allerdings gibt es noch einen zweiten Fehler "Lost Connection during query"
Bei diesem Fehler solltest du dringend die Ursache abstellen, und die liegt wahrschreinlich nicht in deinem Programm
hde

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

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

Beitrag von hubblec4 »

hde hat geschrieben: Bei diesem Fehler solltest du dringend die Ursache abstellen, und die liegt wahrschreinlich nicht in deinem Programm
hde
was für ursachen könnten das denn alles sein? Ich vermute ja auch stark das es mit dem netzwerk oder anderen rechnern die im netzwerk sind zu tun hat.

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

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

Beitrag von hde »

hubblec4 hat geschrieben:"Lost Connection during query"
Wenn die Meldung stimmt, und daran ist eigentlich nicht zu zweifeln, dann stand die Verbindung beim Start der Query und ging mittendrin verloren.
Wen's ein Select war, dann stimmt evtl. "nur" die Anzeige nicht, wenn's aber bei einem Update, Insert oder Delete passiert ist ein ganz saubers Transactionhandling das Wichtigste.
MySQL killt schon mal eine Verbindung per Timeout, niemals aber mitten in einer Query, und dein Programm - hoffentlich - auch nicht. Es sei denn deine Versuche zum Reconnect o. dgl. kommen zur Unzeit (irgendwas per Timer?) :wink: Ich hab das von Michl und mse nicht mehr so genau verfolgt.
Ansonsten tipp ich auf ein sehr instabiles Netz, und das kann viele Ursachen haben.
hde

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

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

Beitrag von hubblec4 »

@hde

der "during query" fehler kommt abundzu wenn was geslöscht geändert oder neu eingetragen wurde.

nach dem SQL befehl (open;sql.text;ExecSQL) kommt immer ein SQLTransaction.Commitretaining.
Alle daten werden auch ordentlich in die DB eingetragen. Bei dem Fehler werden anscheinend die daten vorher noch ordentlich in der DB angelegt.
(konnte das nicht ausgibig testen aber es war immer so der Fall).

Sollte man bevor man etwas in der DB ändert dieses SQLTransaction.Commitretaining ebenfalls ausführen?

Ich bin gestern noch nicht fertig geworden mit dem neuen rechner muss heute nochmal hin, aber erste tests sahen gut aus mit meinem programm.

hde
Beiträge: 556
Registriert: Mi 11. Aug 2010, 02:56

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

Beitrag von hde »

hubblec4 hat geschrieben:der "during query" fehler kommt abundzu wenn was geslöscht geändert oder neu eingetragen wurde.
nach dem SQL befehl (open;sql.text;ExecSQL) kommt immer ein SQLTransaction.Commitretaining.
"Lost Connection during query" sagt aber doch, dass die Verbindung mitten in der Transaction abgebrochen ist. Was also davon in der DB angekommen ist weiß man nicht, es sei denn, man ist Wahrsager. Dann trotzdem einen Commit zu machen entspricht einem ungesicherten Seiltanz über einem Abgrund.

Üblicherweise folgt auf einen solchen Fehler ein Rollback und man wiederholt den Vorgang.
hde

EgonHugeist
Beiträge: 93
Registriert: Di 17. Apr 2012, 22:41

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

Beitrag von EgonHugeist »

Nun noch mein Senf zum Thema:

grundsätzlich wäre es schön, wenn Zeos Events, wie OnConnectionLost etc. untestützen würde. Jede nicht lokale Verbindung oder TimeOuts dieser Art werden derzeit NICHT von Zeos behandelt.
Das derzeitige Team möchte mit 7.2 und meinen Performance upgrades in richtung Beta gehen (auch wenn ich nicht sonderlich glücklich darüber bin, da ich noch fertig bin -> da geht noch mehr!), was mir letztendlich das Einfühen von neuerlich Verhaltensändernden Properties unterbindet.

Somit könnte ich (falls TestCase verfügbar) erst mit 7.3 anfangen, dergleichen Fehler abzufangen, oder kann mir jemand ein TestCase zusammen basteln, welches solche Szenarios auch auf lokaler DB hervorrufen könnte? -> ticket auf SF.NET

@Martin -> toller JOB, wirklich!
ZeosDevTeam

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

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

Beitrag von Michl »

EgonHugeist hat geschrieben:Das derzeitige Team möchte mit 7.2 und meinen Performance upgrades in richtung Beta gehen (auch wenn ich nicht sonderlich glücklich darüber bin, da ich noch fertig bin -> da geht noch mehr!)
Bei mir ists schon lange beta :D (ich nutze zumindest Zeos 7.2alpha efolgreich und ohne größere Probleme (bis auf einen Fehler, den Du ja behoben hast und einem Perfomanceproblem, wo ich lieber SQLdb einsetze (das ist aber ein anderes Thema und liegt wahrscheinlich an mir selber)). Außerdem nutze ich sehr viel SQL zu Fuss, sodaß ich wahrscheinlich die Vorteile von ZEOS nicht wirklich ausreize.
EgonHugeist hat geschrieben:...oder kann mir jemand ein TestCase zusammen basteln, welches solche Szenarios auch auf lokaler DB hervorrufen könnte?
Einen Testcase mit MySQL und Localhost habe ich ja. Den könnte ich, falls Du willst, nochmal auf das Mindeste reduzieren und Dir schicken?!
Eine LostConnection für SQLite3 hatte ich gestern mal gebaut und per SqlApi die vorhandene Connection hart getrennt. Komischerweise stört das Zeos nicht, es findet die Connection ohne Fehlermeldung oder sonstiges immer wieder - merkwürdig. Evtl. müsste man da noch mehr zurücksetzen (evtl. das SQL-Handle nilen, was praktisch aber eigentlich nicht passieren sollte), um ein LostConnection zu simulieren?!

Code: Alles auswählen

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

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

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

Beitrag von hubblec4 »

Ich melde mich mal mit ein paar infos.

Der neue rechner macht seine arbeit hervorragend, bis jetzt wurde mir noch keine Verbindungstrennung gemeldet.
Es scheint so als liefe es jetzt mit diesem rechner super und alle anderen müsste ich dann eben auch mal neu aufsetzen.

@Michl
Ich nutze deinen THachTransaction-Hack und er tut seine arbeit sehr gut.
Bei den anderen rechnern dort im netzwerk brechen die verbindungen immer mal noch ab aber sie werden aufgefangen und eine neue verbindung wird aufgebaut. recht vielen dank nochmal für deine hilfe.

EgonHugeist
Beiträge: 93
Registriert: Di 17. Apr 2012, 22:41

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

Beitrag von EgonHugeist »

@ALL

Hatte gestern mal mit MySQL herumgespielt und siehe da ich konnte diverse Bugs ausmachen und diese bereinigen. Das Connection-Timeout sollte jetzt auch funzen.

um ein Re-Connect via client-lib zu erzwingen fügt folgenden Parameter zu den TZConnection.Properties hinzu:

Code: Alles auswählen

 
MYSQL_OPT_RECONNECT=TRUE
 
desweiteren sollten alle MySQL "Before Realconnect" parameter unterstützt sein:

Code: Alles auswählen

 
  TMySqlOption = (
  MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE,
    MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
    MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE,
    MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT,
    MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
    MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
    MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
    MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
    MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH,
    MYSQL_OPT_BIND,
    MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
    MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
    MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
    MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD,
    MYSQL_OPT_CONNECT_ATTR_DELETE,
    MYSQL_SERVER_PUBLIC_KEY,
    MYSQL_ENABLE_CLEARTEXT_PLUGIN,
    MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
    MYSQL_OPT_SSL_ENFORCE
    );
 
wen es noch interessiert: http://dev.mysql.com/doc/refman/5.7/en/ ... tions.html
Wird einer der Parameter (..bis 5.7) nicht unterstützt, überspringe ich ihn mit Hilfe einer Versionsprüfung der Client-Lib.
Da sind auch

Code: Alles auswählen

 
MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT
 
dabei... -> ging es nicht damit los hier? :P

@Michl,
falls die Änderungen nicht helfen.. mach mir mal ein TestCase fertig. MIT create-script und ein paar Daten. Schön wärs, wenns zu unseren Tests (SVN) passt.
ZeosDevTeam

Antworten