Announcement

Collapse
No announcement yet.

IBX: Transaktionen richtig nutzen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • IBX: Transaktionen richtig nutzen

    Hallo,

    welche Methoden sind empfehlenswert, um mit IBX (4.2) einen schnellen Multiuserbetrieb mit IB 5.6 / IB 6 zu erreichen?

    Konkret habe ich folgende Fragen:

    1) Zwei User ändern den selben Datensatz. Wer als erster speichert, soll "gewinnen". Der zweite soll eine Fehlermeldung erhalten. Wie läßt sich das realisieren?

    2) Die Änderung eines Users A an einem Datensatz sollen alle anderen User mitbekommen, indem (manuell) ein TIBDataset.Refresh aufgerufen wird. Hierzu muss A seine Änderung aber mittels COMMIT festschreiben. Muss also manuell nach jedem POST ein CommitRetaining gemacht werden???

    3) Transaktionen sollen bekannterweise so kurz wie möglich sein. Sobald ich aber eine TIBDataset öffne, um damit beispielsweise eine Liste zu füllen, ist die Transaktion offen und bleibt es auch, solange die Query geöffnet ist. Ist das ok? Ändert der User nun in der Liste einen Eintrag, wird das UPDATE-Statement in TIBDataset.ModifySQL aufgerufen. Läuft das unter der selben Transaktion? Wann ist ein Commit(Retaining) sinnvoll?

    4) Ist es sinnvoll, für jedes TIBDataset ein eigene TIBTransaction zu definieren? Das würde ich eigentlich gerne vermeiden...

    Gibt es irgendwo gute Grundlagenartikel oder Literatur? Freue mich über jeden Hinweis!

    Beste Grüße,
    Georg

  • #2
    Hallo,

    zu Frage 1: <br>
    Dank der Multigenerationenarchitektur (Versioning) des InterBase ist dies das Standardverhalten. Die TIBTransaction-Instanz sollte dabei die folgende Konfiguration verwenden:
    <pre>
    read_committed
    rec_version
    nowait
    </pre>

    zu Frage 2: <br>
    Eine Transaktion sollte in der Regel immer mit <b>Commit</b> bestätigt werden, der Einsatz von <b>CommitRetaining</b> sollte aufgrund der damit verbundenen Nebenwirkungen nur in begründeten Fällen erfolgen. Da mit einem Commit automatisch auch das Schließen des Datasets verbunden ist, erhält der Client beim anschliessenden Öffnen automatisch eine neue Transaktionsnummer und somit den neuesten Stand des Datensates.

    zu Frage 3: <br>
    Generell ist es eine gute Idee, alle "Nachschlagetabellen" lokal im Client zwischenzupuffern, so dass die Datenmenge nur kurzzeitig für das Kopieren der Daten offen sein muss. Im Fall von IBX kann man dazu eine <b>TClientDataset</b>-Instanz verwenden (ab Delphi 6 soll TClientDataset auch in der Professional-Version von Delphi enthalten sein). Die BDE- und ADO-Leute haben es da besser, hier stehen mehr Alternativen zur Verfügung.

    Außerdem ist es in einer typischen C/S-Umgebung unüblich, dass ein Datensatz aus einer offenen Datenmenge ausgewählt und geändert wird. Der "normale" Weg sieht statt dessen so aus: <br>
    1. Benutzer ruft ein Auswahlfenster auf, in dem via SELECT Datensätze zur Auswahl angeboten werden. <br>
    2. Nach der Auswahl wird diese Datenmenge und das Auswahlfenster geschlossen und der konkrete Datensatz einzeln (DBEdits etc.) im Hauptfenster angezeigt. <br>
    3. Beim UPDATE ist nun nur ein einziger Datensatz in der Datenmenge, die nach dem COMMIT automatisch geschlossen wird. <br>
    4. Soll ein weiterer Datensatz bearbeitet werden, wiederholt sich das Ganze. <br>
    In diesem Szenario wird CommitRetaining überhaupt nicht benötigt, der InterBase kann somit sehr effektiv arbeiten.

    zu Frage 4: <br>
    Das kommt darauf an. Eine eigene TIBTransaction-Instanz wird nur dann benötigt, wenn die Datenbankzugriffe als Transaktion unabhängig von den anderen Zugriffen gesteuert werden sollen. Es ist besser, zwei Instanzen einzusetzen als alle Datenmengen über CommitRetaining am Leben zu erhalten, obwohl dies nicht in jedem Fall notwendig ist.

    zu Frage 5: <br>
    In einem guten InterBase-Buch. IBX setzt im Bereich der Transaktionen direkt auf den InterBase auf, ohne selbst einzugreifen (von minimalen Ausnahmen einmal abgesehen). Somit sind spezielle IBX-Bücher nicht notwendig (was die Tranaktionssteuerung angeht).
    &#10

    Comment


    • #3
      Hallo,

      erst mal vielen Dank für die ausführliche Antwort. Dennoch möchte ich in einigen Punkt noch etwas ins Detail gehen bzw. nachhaken:

      zu 1) Die angegebenen Parameter habe ich wie angegeben gesetzt, d.h. es ist "read-commited" eingestellt. Dennoch erhält ein zweiter User, der einen bereits geänderten Datensatz ändert, KEINE Fehlermeldung. Woran kann das liegen? Eine Änderung auf "no_rec_version" bringt auch nichts, da dies nur eine Fehlermeldung bringt, wenn der andere User den Datensatz in einer OFFENEN Transaktion bearbeitet, hat er sie bereits COMMITed, passiert auch hier nichts.

      zu 3) Ich sehe ein, dass in einer C/S-Umgebung andere Regeln auch für die Benutzeroberfläche entstehen. Dennoch soll aber doch bestimmt direkt in einer Liste ein Datensatz gelöscht werden können. Hier stellt sich aber eine weitere Frage, die ich am folgenden Ablauf verdeutlichen möchte:

      - TIBDataset mit gewünschtem SelectSQL (das mehrere Datensätze zurückliefert) und DeleteSQL belegen
      - TIBDataset.StartTransaction
      - TIBDataset.Open, Anzeige der Daten in einem Grid
      (Transaktion ist nun so lange offen, wie der User es will)
      - User will editieren -> TIBDataset.Commit, dann im neuen Fenster neue Query abschicken, die nur den einen Datensatz bringt
      (jetzt kommt's
      - User will löschen -> TIBDataset.Delete aufrufen, wodurch die eingestellte DeleteQuery aufgerufen wird, ABER UNTER WELCHER TRANSAKTION????
      - User schließt das Listenfenster -> TIBDataset.Commit/Close

      Werden SELECT und DELETE in der gleichen Transaktion ausgeführt? Wie wird sichergestellt, dass ein Löschen sofort commited wird? Ist hier ausnahmsweise die Verwendung von CommitRetaining sinnvoll?

      zu 5) Da die Auswahl an InterBase-Büchern sehr gering ist, ist es ein Leichtes, alle Verfügbaren zu kennen; daraus kann man prima die Funktionsweise von InterBase erlernen. Was ich jedoch bisher kaum gesehen habe, ist eine intensive Auseinandersetzung mit InterBase auf Applikationsebene. Man liest zwar ständig, dass z.B. Transaktionen nur so kurz wie möglich offen gehalten werden sollen etc., aber wie das am besten mit Delphi und den verfügbaren Komponenten (IBX/IBO) gemacht werden kann, findet sich kaum, zumindest nicht in zusammenhängender Form. Was ich suche ist eine vernünftige IB-Applikations-"Architektur" (am liebsten auf Basis von IBX), die man für eigene (neue!) Projekte übernehmen kann. Ich stehe hier vor der Aufgabe, eine Applikation zu bauen, die um die 200 Tabellen in der IB-Datenbank halten muss. Da ist allein die Frage nach einer geschickten Aufteilung in Datenmodule nicht trivial.
      Ich werde mich jetzt nochmal intensiv mit IBSrcArc beschäftigen, vielleicht hilft mir das.

      Bleibt mir ansonsten nur ein Workshop bei HK? ;-)

      Beste Grüße,
      Geor

      Comment


      • #4
        Hallo,

        zur Frage 1: <br>
        Die Vorgehensweise muss nur in einem Punkt erweitert bzw. besser erklärt werden :-) <br>
        1. Benutzer startet Transaktion <br>
        2. Benutzer liest Datensatz ein <br>
        3. Benutzer macht einen beliebigen Dummy-Schreibzugriff auf diesen Datensatz, damit erhält er die eigene Transaktionsnummer <br>
        4. Benutzer editiert in Ruhe diesen "gesperrten" Datensatz <br>
        5. Benutzer macht sein UPDATE und Committed die Transaktion <br>
        Wenn der zweite Client diese Schritte abarbeiten will, erhält er im Schritt 3 immer dann ein Veto vom InterBase (no_rec_version), wenn vor ihm bereits ein anderer Client dies aufgerufen hat.

        zur Frage 3: <br>
        Hier würde ich in jedem Fall nach dem Abschicken der DELETE-Anweisung ein COMMIT aufrufen und die Datenmenge neu aufbauen lassen (d.h. neues SELECT).

        zur Frage 5: <br>
        Derartige Fragen sind immer eines der Hauptthemen der Workshops zu den Entwickler-Konferenzen. Zum Beispiel kümmere ich mich hier zur Entwickler-Konferenz am Freitag von 09..17 Uhr um dieses Thema. Falls es eine neue Auflage des Buchs gibt, werde ich dieses Thema aber auch dort ansprechen (wenn ich die zusätzliche Seitenanzahl dafür "genehmigt" bekomme)

        Comment


        • #5
          Hallo Andreas,<br>
          ich gebe georg recht, es gibt wirklich wenige Beispielanwendungen in diesem Bereich.Theorie ist ja schön und gut aber ein praktisches Beispiel ist noch besser )<br>
          Ich habe auch eine Frage zu Multiuser - Anwendung undzwar:<br>
          wie läuft das mit " Set Transaction isolation level snapshot table stability; " wird dabei der datensatz gesperrt oder die ganze Tabelle?<br>
          Womit erzeuge ich die Transaction ? mit TIBTransaction oder wie kann ich das steuert?<br>

          Regard

          Comment


          • #6
            Hallo Andreas,<br>
            ich gebe georg recht, es gibt wirklich wenige Beispielanwendungen in diesem Bereich.Theorie ist ja schön und gut aber ein praktisches Beispiel ist noch besser )<br>
            Ich habe auch eine Frage zu Multiuser - Anwendung undzwar:<br>
            wie läuft das mit " Set Transaction isolation level snapshot table stability; " wird dabei der datensatz gesperrt oder die ganze Tabelle?<br>
            Womit erzeuge ich die Transaction ? mit TIBTransaction oder wie kann ich das steuert?<br>

            Regards
            Volker Jahn

            Comment


            • #7
              Hallo,

              die Diskussion endete am 22. September <b>2000</b> - ist also über ein Jahr alt. Inzwischen gibt es komplexe IBX-Beispielprojekte: <br>
              a) hier im Forum unter <i>Delphi | IBX | RedSys</i>, und<br>
              b) in meinem Buch <i>InterBase Datenbankentwicklung mit Delphi</i><br>
              In meinem IBX-Buch ist auch das folgende Beispiel zu finden, dass diese "exotischen" Isolation Level aktiviert:
              <pre>
              procedure TForm1.RadioGroup1Click(Sender: TObject);
              begin
              IBDataSet1.Active := False;
              IBDatabase1.Connected := False;
              IBDatabase1.Params.Values['user_name'] := 'sysdba';
              IBDatabase1.Params.Values['password'] := 'masterkey';
              IBTransaction1.Params.Clear;
              case RadioGroup1.ItemIndex of
              1 : begin
              with IBTransaction1 do
              begin
              Params.Add('read_committed');
              Params.Add('rec_version');
              Params.Add('nowait');
              IBDatabase1.Connected := True;
              IBDataSet1.Active := True;
              end;
              end;
              2 : begin
              with IBTransaction1 do
              begin
              Params.Add('nowait');
              Params.Add('consistency');
              Params.Add('lock_write=NameDerTabelle');
              Params.Add('exclusive');
              IBDatabase1.Connected := True;
              IBDataSet1.Active := True;
              end;
              end;
              3 : begin
              with IBTransaction1 do
              begin
              Params.Add('nowait');
              Params.Add('consistency');
              Params.Add('lock_write=NameDerTabelle');
              Params.Add('shared');
              IBDatabase1.Connected := True;
              IBDataSet1.Active := True;
              end;
              end;
              end;
              Memo1.Lines := IBTransaction1.Params;
              end;
              </pre>
              Über <b>TIBTransaction.Params</b> kann man alles das anfordern, was vom InterBase unterstützt und in seiner Dokumenation beschrieben wird. Es wird die komplette Tabelle gesperrt, wobei man sogar jeden Lesezugriff (SELECT) auf diese Tabelle blockieren kann

              Comment


              • #8
                Vielen dank Andreas ,<br>
                ich habe mir dein neues Buch besorgt und kann das beispiel nachvollziehen.
                Das Buch ist wirklich gut, gut Aufgebaut und immer Beispiele <br>
                Gruß Volker Jahn

                Comment

                Working...
                X