Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   To Commit or not to commit (https://www.delphipraxis.net/190181-commit-not-commit.html)

Zwirbel 8. Sep 2016 10:04

Datenbank: Firebirdd • Version: 3 • Zugriff über: Seattle

To Commit or not to commit
 
Hallo,

das man in einer echten Datenbank (Firebird) z. B. einen Datensatz nicht einfach nur einfügt sondern das ganze noch commiten muss, ist mir klar. Nun stellte ich aber gerade fest, dass ein Commit das ich abgesetzt habe, überhaupt nichts brachte. Ich hatte es einfach mal auskommentiert und trotzdem sind alle Tabellen die ich gefüllt habe ordnungsgemäß aufgefüllt worden. Auch ein paar "ALTER SEQUENCE "%s" RESTART WITH %d" die ich noch abgesetzt habe sind alle in der Datenbank angekommen. Nun frage ich mich, durch welchen Mechanismus ist das passiert?

Ich verwende eine TFDConnection-Komponente (namens "dbsAM_FB") und eine TFDTransaction-Komponente. In dieser ist das Options.AutCommit auf "False" gesetzt. Zum Einfügen der Datensätze verwende ich einen TFDQuery. Datensätze füge ich ein mit "qry_FB.ExecSQL(InsertSQL);".

Was bewirkt denn nun, dass ohne explizites "dbsAM_FB.Commit;" die Operationen (Einfügen und ALTER SEQUENCE) überhaupt nachhaltig sind?

Mal der etwas verkürzte Code, der die Daten per INSERT einträgt:

Delphi-Quellcode:
        tbl_Pdx.TableName := TableNames[i];
        tbl_Pdx.Open;
        try
          try
            tbl_Pdx.First;
            InsertFieldNames := '';
            InsertFieldValues := '';
            qry_FB.SQL.Clear;

            { Zuerst sammeln wir die Felder für das Insert-Statement. }
            for k := 0 to Pred(tbl_Pdx.Fields.Count) do begin
              FieldNameUpper := RenamedField(TableName, tbl_Pdx.Fields[k].FieldName);
              if FieldNameUpper <> '' then begin
                InsertFieldNames := InsertFieldNames + Format('"%s", ', [FieldNameUpper]);
                InsertFieldValues := InsertFieldValues + Format(':%s, ', [FieldNameUpper]);
                FieldNames[k] := FieldNameUpper;
              end else begin
                FieldNames[k] := '';
              end;
            end;
            InsertFieldNames := Copy(InsertFieldNames, 1, Length(InsertFieldNames)-2);
            InsertFieldValues := Copy(InsertFieldValues, 1, Length(InsertFieldValues)-2);
            InsertSQL := Format('INSERT INTO "%s" (%s) VALUES (%s)', [TableName, InsertFieldNames, InsertFieldValues]);
            qry_FB.SQL.Add(InsertSQL);

            { Jetzt sammeln wir die Felder für das "Params". }
            for k := 0 to Pred(tbl_Pdx.Fields.Count) do begin
              FieldNameUpper := tbl_Pdx.Fields[k].FieldName;
              if FieldNameUpper <> '' then begin
                FieldNameUpper := tbl_Pdx.Fields[k].FieldName;
                qry_FB.Params.CreateParam(tbl_Pdx.Fields[k].DataType, FieldNameUpper, ptInput);
              end;
            end;

            { Alle Datensätze der Quelltabelle durchlaufen. }
            for j := 0 to Pred(RecordCount) do begin
              FMeter.CurrentValue := Succ(j);
              Percent := (100 * j) div RecordCount;
              for k := 0 to Pred(tbl_Pdx.Fields.Count) do begin
                if FieldNames[k] = '' then Continue; // Ein Feld das in der Zieltabelle nicht mehr vorhanden ist überspringen

                FieldNameMixed := tbl_Pdx.Fields[k].FieldName;
                FieldNameUpper := FieldNames[k];

                { Nun die Werte je nach Datentyp übertragen von der Quelle ins Ziel }
                case tbl_Pdx.Fields[k].DataType of
                  ftString          :
                    if FieldNameMixed <> 'LoginPassword' then begin
                      qry_FB.ParamByName(FieldNameUpper).AsString := tbl_Pdx.FieldByName(FieldNameMixed).AsString;
                    end else begin
                      qry_FB.ParamByName(FieldNameUpper).AsString := GetStrHashBobJenkins(tbl_Pdx.FieldByName(FieldNameMixed).AsString);
                    end;
                end; // case tbl_Pdx.Fields[k].DataType of
              end; // for k := 0 to Pred(tbl_Pdx.Fields.Count) do

              { Wenn nur simuliert werden soll, keine Daten eintragen. }
              if not chkSimulation.Checked then
                qry_FB.ExecSQL(InsertSQL);
              tbl_Pdx.Next;

              { Daten nur in größeren Brocken an die Datenbank übertragen. }
              if (j mod 5000) = 0 then begin
                if not chkSimulation.Checked then
                  dbsAM_FB.Commit;
              end;
            end; // for j := 0 to Pred(tbl_Pdx.RecordCount) do

            if FStoped then Break; // Bricht die komplette Konvertierung sofort ab
            FSkip := False;
          finally
            tbl_Pdx.Close;
          end;
Danke im Voraus. Gruß, Markus

Neutral General 8. Sep 2016 10:11

AW: To Commit or not to commit
 
Die Queries haben noch ne Property AutoCommit die standardmäßig auf true steht

Zwirbel 8. Sep 2016 10:15

AW: To Commit or not to commit
 
Zitat:

Zitat von Neutral General (Beitrag 1347174)
Die Queries haben noch ne Property AutoCommit die standardmäßig auf true steht

Meine Query-Komponente sieht so aus:
Delphi-Quellcode:
object qry_FB: TFDQuery
  Connection = dbsAM_FB
  Left = 497
  Top = 609
end
Das Property "UpdateUptions.AutoCommitUpdates" steht also noch auf dem Defaultwert "False".

Allerdings entdecke ich gerade, dass das Property "Transaction" der Query nicht gesetzt ist. Das sollte man sicherlich tun.

Zwirbel 8. Sep 2016 12:05

AW: To Commit or not to commit
 
Zitat:

Zitat von Neutral General (Beitrag 1347174)
Die Queries haben noch ne Property AutoCommit die standardmäßig auf true steht

Leider liefert die in Delphi integrierte Hilfe mal wieder nichts brauchbares wenn man Infos zu Properties einer Kompo haben will. Aber Google spuckt dann einen Link mit brauchbaren Infos aus http://developers-club.com/posts/273549/. Und bei mir ist "Options.AutoStart" in der Tat "True", allerdings ist "Options.AutoStop" auf "False", der Default wäre aber "True", kann mich nicht entsinnen das verändert zu haben. "Options.DisconnectAction" steht auf "xdCommit". Also dürfte das der Auslöser dafür sein, dass a) automatisch Transaktionen starten und b) spätestens wenn die Verbindung beendet wird, dann wird commited.

Wieder was gelernt.

Sherlock 8. Sep 2016 12:10

AW: To Commit or not to commit
 
Übrigens: DDL braucht im Gegensatz zu DML kein Commit. Kurz und vereinfacht gesagt: Alles was die Struktur ändert kann ohnehin nicht Rückgängig gemacht werden, demzufolge spart man sich die Commits. Und ein Alter irgendwas ändert die Struktur...

Sherlock

Zwirbel 8. Sep 2016 12:12

AW: To Commit or not to commit
 
Zitat:

Zitat von Sherlock (Beitrag 1347190)
Übrigens: DDL braucht im Gegensatz zu DML kein Commit. Kurz und vereinfacht gesagt: Alles was die Struktur ändert kann ohnehin nicht Rückgängig gemacht werden, demzufolge spart man sich die Commits. Und ein Alter irgendwas ändert die Struktur...

Danke für den Hinweis. Gruß, Markus

Bernhard Geyer 8. Sep 2016 12:19

AW: To Commit or not to commit
 
Zitat:

Zitat von Sherlock (Beitrag 1347190)
Übrigens: DDL braucht im Gegensatz zu DML kein Commit. Kurz und vereinfacht gesagt: Alles was die Struktur ändert kann ohnehin nicht Rückgängig gemacht werden, demzufolge spart man sich die Commits. Und ein Alter irgendwas ändert die Struktur...

AFAIK kann das Oracle.
Oracle hat auch einen "Abfalleimer" für gelöschte Tabellen.
Wenn man sich wundert das die Datenbank nicht kleiner wird sollte man die Tabellen im "Abfalleimer" entgültig löschen.

Zwirbel 8. Sep 2016 12:28

AW: To Commit or not to commit
 
Zitat:

Zitat von Sherlock (Beitrag 1347190)
Übrigens: DDL braucht im Gegensatz zu DML kein Commit. Kurz und vereinfacht gesagt: Alles was die Struktur ändert kann ohnehin nicht Rückgängig gemacht werden, demzufolge spart man sich die Commits. Und ein Alter irgendwas ändert die Struktur...

Nun da ich explizit startende Transactions ausgeschaltet habe und das "ALTER SEQUENCE "%s" RESTART WITH 0" ohne eine eingeleitete Transaction absetzen will kriege ich eine Exception:
Delphi-Quellcode:
  226: 08.09.2016 13:16:33: Error: @@@
Modul: [FireDAC][Phys][FB]Dynamic SQL Error
SQL error code = -901
invalid transaction handle (expecting explicit transaction start)
ErrorId: 1008
Msg: TfrmAMU.ClearTables: Table: [TA_AssetBlock]
Error: [FireDAC][Phys][FB]Dynamic SQL Error
SQL error code = -901
invalid transaction handle (expecting explicit transaction start)
Nun habe ich auch um das ganze ALTER SEQUENCE Gedöns eine Transaction gestartet und dann klappt es wieder.

tsteinmaurer 8. Sep 2016 14:34

AW: To Commit or not to commit
 
Zitat:

Übrigens: DDL braucht im Gegensatz zu DML kein Commit.
Hier unterscheidet sich Firebird von Oracle. In Firebird muss grundsätzlich DDL auch committed werden. Wird halt oft automatisch gemacht, z.b. durch AUTODLL in isql oder halt auch AutoCommit Einstellungen im Client.

Thomas

jobo 8. Sep 2016 15:04

AW: To Commit or not to commit
 
Zitat:

Zitat von tsteinmaurer (Beitrag 1347200)
Zitat:

Übrigens: DDL braucht im Gegensatz zu DML kein Commit.
Hier unterscheidet sich Firebird von Oracle. In Firebird muss grundsätzlich DDL auch committed werden. Wird halt oft automatisch gemacht, z.b. durch AUTODLL in isql oder halt auch AutoCommit Einstellungen im Client.

Thomas

Sowas hatte ich für Firebird auch im Kopf, war mir aber nicht sicher.

Wichtig für die Arbeit mit Systemen, die sich wie Oracle verhalten, ist vielleicht im Einzelfall bei DDL ohne Autocommit:
DDL macht eigenständig ein Commit, man kann es nicht verhindern, deswegen "braucht" es kein DDL.
Ignoriert man das, führt es leicht zu nicht gewollten Daten-Commits.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:54 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz