Announcement

Collapse
No announcement yet.

Probleme mit Transaction

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

  • Probleme mit Transaction

    Hallo,

    ich habe eine StoredProcedure, die in meienr Tabelle die größte Kundennummer heraussucht und um 1 erhöht. Will ich diese nun aus dem Programm starten ergibt sich folgendes Problem:

    procedure TKundeStammForm1.CheckBox1Click(Sender: TObject);

    var

    id_neu : string;

    ok : boolean;

    begin

    if CheckBox1.Checked = true then

    begin

    repeat

    ok := true;

    <b>{if DataModule1.ADOConnection1.inTransaction = true then
    DataModule1.ADOConnection1.commitTrans;}</b>

    DataModule1.ADOConnection1.BeginTrans;

    DataModule2.ADOStoredProc_KundenID.execProc;

    id_neu := DataModule2.ADOStoredProc_KundenID.FieldByName
    ('ID_NEU').Value;

    try

    DBEdit12.Field.ASString := id_neu;

    DataModule1.ADOConnection1.commitTrans

    except

    {on E: EIBError.SQLCode -803 DO }

    ok := false;

    DataModule1.ADOConnection1.RollbackTrans;

    end;

    until ok;

    if DataModule1.ADOConnection1.InTransaction = true then
    DataModule1.ADOConnection1.commitTrans;

    end;

    end;

    Wenn ich die erste if-Bedingung verwende erhalte ich bei Anwendereingabe: CheckboxChecked := true; -> false; -> true; -> die Fehlermeldung Transaction is not active.

    Verwende ich die if-Bedingung nicht, erhalte ich zwar keine Fehlermeldung, aber bei einer neuen Eingabe eines Kunden erhalte ich die gleiche Kundennummer wie vorhin. Das Post-Ereignis habe ich immer mit BeginTrans gestartet und mit Commit bzw. Rollback beendet. Die neue Kundennummer ist auch in der Tabelle vorhanden. Bei einem neustart des Programms funktioniert die StoredProcedure wieder. Wer kann mir das erklären ? Ein paar grundsätzliche Angaben zu der Verwendung von Transactionen mit ADO wäre auch nicht schlecht.

    Ich hoffe es kann mir schnell einer helfen, denn ich bin etwas unter Zeitdruck.

    Danke, Gruß Elke

  • #2
    Hallo,

    ich glaube nicht, das es an ADO liegt, sondern eher an SIBProvider. Normalerweise würde man im Fall des Microsoft SQL Server 2000 zum <i>Profiler</i> greifen, um sich anzuschauen, welche SQL-Anweisungen der OLE DB-Provider zur Datenbank schickt. Beim InterBase steht diese Option für ADO (im Gegensatz zur BDE/IBX) nicht zur Verfügung.

    Was passiert, wenn diese Funktion eine <b>eigene</b> (zweite) TADOConnection-Instanz erhält? Welcher Wert wird für die TADOConnection-Eigenschaft <i>IsolationLevel</i> verwendet

    Comment


    • #3
      Hallo Andreas,

      1. wenn ich aus dieser Transaction heraus eine neue Transaction starten möchte erscheint die gleiche Fehlermeldung: EIBClientError bzw. OLException.

      2. Ich verwende den IsolationLevel RepeatableRead.

      Wo kann ich denn Informationen zu dem IBProvider herbekommen ? Ich weiß, dass er nicht gut kommentiert ist.

      Gruß Elk

      Comment


      • #4
        Hallo Elke,

        ändere einfach mal den Isolationslevel auf <b>read committed</b>. Das könnte abhängig vom Anwendungsdisign einige Deiner Probleme lösen.

        Hast Du Dich schon einmal intensiv mit den verschiedenen Isolationsleveln von Interbase beschäftigt? Wenn Du ernsthaft mit SQL-Datenbanken arbeiten möchtest ist das Verstehen von Transaktion Grundvoraussetzung.

        Tschüß

        Torste

        Comment


        • #5
          Hallo Torsten,

          mit ReadCommitted hatte ich es auch schon versucht, ändert aber nichts.

          In dem Buch von Andreas steht ja einiges über Transaktionen drin. Das hab ich mir nun auch schon mehrfach durchgelesen (Finde ich übrigens Klasse und auch für Anfänger nicht zu schwer, wie es im Forum schon mal bemängelt wurde). Aber meistens treten ja doch Probleme auf, die ein Buch alleine nicht beantworten kann.

          Gruß Elk

          Comment


          • #6
            Hallo,

            was passiert, wenn eine <b>zweite</b> (separate) TADOConnection-Instanz für den Aufruf der Stored Procedure verwendet wird und dort nach jedem Aufruf die ADO-Verbindung wieder getrennt wird? ADO (genauer gesagt OLE DB) verwendet einen automatischen Datenbankverbindungs-Pool, so dass das ständige trennen/öffnen der Datenbankverbindung keine negativen Performance-Auswirkungen hat (genauer gesagt: ist zeitlich nicht messbar). Das wäre zumindestene einen Versuch wert, um die Ursache des Problems besser eingrenzen zu können

            Comment


            • #7
              Hallo Andreas,

              wenn ich eine zweite ADOConnetion aufrufe erhalte ich die Meldung, dass bereits eine Transaction aktiv ist.

              Gruß Elk

              Comment


              • #8
                Hallo Andreas,

                nach langem Probieren denke ich, dass der Commit Aufruf irgendwie nicht richtig verarbeitet wird. Wenn ich nämlich diesen Code eingebe passiert folgendes:

                <b>repeat ...

                until ok;

                if DataModule1.ADOConnection1.inTransaction = true then

                DataModule1.ADOConnection1.commitTrans; </b>// Transaktion ist aktiv und die then Bedingung wird ausgeführt.

                Erneutes Ausführen der repeat Schleife

                <b>if DataModule1.ADOConnection1.inTransaction = true then

                DataModule1.ADOConnection1.commitTrans;</b> // die then Bedingung wird wieder ausgeführt, also kann die erste nicht zur Beendigung der Transaktion geführt haben

                <b> DataModule1.ADOConnection1.BeginTrans; </b>// Die Anwendung bricht noch vor dem Start der Transaction mit der Fehlermeldung "Transaktion ist aktiv" ab.

                Dennoch erscheinen die neuen Daten direkt nach deem Speichern in der InterBase Tabelle sowie in einer aus dem Programm aufgrufenen Tabelle. Nur meine Stored Procedure scheint nicht auf die aktualisierte Tabelle zuzugreifen. Woran kann das liegen ? So langsam bin ich am Verzweifeln. Bitte hilf mir

                Gruß Elk

                Comment


                • #9
                  Hallo,

                  ich bin noch einmal alle Fehlermöglichkeiten durchgegangen und auf folgende Frage gestoßen:

                  Zum Einfügen meines Datensatzes gehe ich folgendermaßen vor:

                  ich beginne mit DataSet3.Insert

                  dann kommt die StoredProcedure, die mit einer try DataSet3.CommitTrans Anweisung eingeleitet wird. In dem Except Zweig folgt die Stored Procedure.

                  Die Stored Procedure wird mit Commit oder Rollback abgeschlossen.

                  Danach kommt die Post Anweisung welche wiederum mit Commit oder Rollback abgeschlossen wird.

                  Nun habe 2 Anweisungen abgeschlossen, aber es waren 3 Transaktionen gestarted. Was passiert nun eigentlich mit der Insert Anweisung nach Post bleibt die alte Transaktion aktiv, obwohl ich eine neue Insert Anweisung starte ? Dem scheint jedenfalls so zu sein, wenn ich nämlich während der Laufzeit in den Fenstern blättere und wieder zu der Eingabe zurückkehre wird mir wieder der alte Datensatz angezeigt.

                  Kann dort das Problem liegen ? Was soll ich tun ?

                  Gruß Elk

                  Comment


                  • #10
                    Hallo,

                    angenommen, ich arbeite mit dem <i>Microsoft SQL Server 7/2000</i>. Bei derartigen Problemen würde ich das SQL-Server-Tool <i>Profiler</i> aufrufen, um mir dort alle SQL-Anweisungen auflisten zu lassen, die mein Programm (genauer gesagt der OLE DB-Provider) zur SQL-Datenbank schickt. Parallel dazu würde ich auch die Transaktionsnummern mit anzeigen lassen, so dass ich beim Microsoft SQL Server jederzeit den Sonderfall einer "nested Transaction" erkennen und damit in meiner Anwendung darauf reagieren kann.

                    In diesem Fall (ich schaue mir das Ergebnis direkt auf der Seite des Servers an) brauche ich nicht lange in der Dokumentation des OLE DB-Providers zu suchen, da wichtig ist "was hinten rauskommt".

                    Im Fall des ADO-Zugriffs auf den InterBase gibt es viele Probleme: <br>
                    1. kein vollwertiger OLE DB-Provider <br>
                    2. keine Dokumentation <br>
                    3. kein Gegenstück zum <i>Profiler</i>, um sich die SQLs und Transaktionen anschauen zu können <br>
                    Ich habe vor Wochen nicht ohne Grund davon abgeraten, ein komplettes InterBase-Projekt mit ADO zu entwickeln.

                    Als Folge der 3 Probleme bleibt nur die "Versuch-und-Irrtum"-Programmierweise übrig. Die ist zeitaufwendig und nervtötend, aber das stand ja am Anfang schon fest.

                    Was passiert, wenn alle Transaktionsanweisungen auskommentiert werden? Statt dessen wird am Ende nur ein Commit abgeschickt und danach sofort die TADOConnection-Instanz geschlossen und beim nächsten Schritt neu geöffent

                    Comment


                    • #11
                      Hallo Andreas,

                      Wenn ich versuche die Transaction zu schließen tut sich entweder gar nichts mehr, oder ich erhalte die Meldung " kann diese Anweisung nicht inmitten einer Transaktion ausführen". Trotzdem verstehe ich nicht so ganz wo hier das Problem liegt, denn im DBGrid ist der neue Datensatz eingefügt und die Tabelle ist im Insert Modus, genau wie gewollt. Der Fehler tritt nur bei den Eingabefeldern auf. Was würdest Du vorschlagen um das Problem zu umgehen. Alles auf einen anderen Server umzustellen ist technisch unmöglich. Ein kompletter Verzicht auf ADO ist mir wegen der Vorgaben meines Professors nicht möglich. Es bliebe nur, die handhabung der StoredProcedure. Kann ich die vielleicht anders einbinden ?

                      Gruß Elk

                      Comment


                      • #12
                        Hallo Elke,

                        ich habe einmal ein kleines Beispielprojekt mit dem SIBProvider zusammengebaut, das 2 unabhängige Transaktionen verwendet und einige Statusmeldung in einer TMemo-Instanz ausgibt. Zuerst das Ergebnis:
                        <pre>
                        Connected...
                        Transaktion gestartet...
                        Datenmenge geöffnet...
                        2.Connected...
                        2.Transaktion gestartet...
                        Ergebnis: 1
                        ...2.Transaktion committed
                        ...2.Disconnect
                        ...Datenmenge geschlossen
                        ...Transaktion committed
                        ...Disconnect
                        </pre>
                        Beide TADOConnection-Instanzen können unabhängig voneinander die Transaktion steuern. Wenn bei Dir bereits an dieser Stelle ein Problem auftritt, muss das an den anderen, zu diesem Zeitpunkt offenen Datenmengen liegen, die die gleiche Verbindung nutzen.

                        Die Implementierung meines Testprogramms sieht so aus:
                        <pre>
                        { ************************************************** **************
                        Autor : Andreas Kosch
                        Compiler : Delphi 6.0 Enterprise
                        Betriebssystem : Windows 2000 SP2
                        Erstellt am : 30.08.2001
                        Beschreibung : Test mit sibprovi.SIBProvider

                        CREATE TABLE LastValue (
                        ID INTEGER NOT NULL PRIMARY KEY,
                        Wert INTEGER)

                        CREATE TABLE TestTbl (
                        ID INTEGER NOT NULL PRIMARY KEY,
                        Wert INTEGER NOT NULL,
                        Info VARCHAR(10) NOT NULL)
                        ************************************************** ************** }

                        unit Unit1;

                        interface

                        uses
                        Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
                        Dialogs, DB, ADODB, StdCtrls, ExtCtrls, DBCtrls, Grids, DBGrids;

                        type
                        TForm1 = class(TForm)
                        ADOConnectionMain: TADOConnection;
                        ADOConnectionLastValue: TADOConnection;
                        ADODataSetMain: TADODataSet;
                        ADODataSetMainID: TIntegerField;
                        ADODataSetMainWERT: TIntegerField;
                        ADODataSetMainINFO: TStringField;
                        DataSourceMain: TDataSource;
                        DBGrid1: TDBGrid;
                        DBNavigator1: TDBNavigator;
                        MemoLog: TMemo;
                        ButtonOpen: TButton;
                        ButtonClose: TButton;
                        ButtonTest: TButton;
                        ADODataSetLastValue: TADODataSet;
                        ADODataSetLastValueWERT: TIntegerField;
                        procedure ButtonOpenClick(Sender: TObject);
                        procedure ButtonCloseClick(Sender: TObject);
                        procedure ButtonTestClick(Sender: TObject);
                        private
                        { Private-Deklarationen }
                        public
                        { Public-Deklarationen }
                        end;

                        var
                        Form1: TForm1;

                        implementation

                        {$R *.dfm}

                        procedure TForm1.ButtonOpenClick(Sender: TObject);
                        begin
                        ADOConnectionMain.Connected := True;
                        MemoLog.Lines.Add('Connected...');
                        ADOConnectionMain.BeginTrans;
                        MemoLog.Lines.Add(' Transaktion gestartet...');
                        ADODataSetMain.Active := True;
                        MemoLog.Lines.Add(' Datenmenge geöffnet...');
                        end;

                        procedure TForm1.ButtonCloseClick(Sender: TObject);
                        begin
                        ADODataSetMain.Active := False;
                        MemoLog.Lines.Add(' ...Datenmenge geschlossen');
                        Application.ProcessMessages;
                        ADOConnectionMain.CommitTrans;
                        MemoLog.Lines.Add(' ...Transaktion committed');
                        Application.ProcessMessages;
                        ADOConnectionMain.Connected := False;
                        MemoLog.Lines.Add('...Disconnect');
                        end;

                        procedure TForm1.ButtonTestClick(Sender: TObject);
                        begin
                        ADOConnectionLastValue.Connected := True;
                        MemoLog.Lines.Add('2.Connected...');
                        ADOConnectionLastValue.BeginTrans;
                        MemoLog.Lines.Add(' 2.Transaktion gestartet...');
                        ADODataSetLastValue.Active := True;
                        MemoLog.Lines.Add('Ergebnis: ' + ADODataSetLastValueWERT.AsString);
                        ADODataSetLastValue.Active := False;
                        ADOConnectionLastValue.CommitTrans;
                        MemoLog.Lines.Add(' ...2.Transaktion committed');
                        Application.ProcessMessages;
                        ADOConnectionLastValue.Connected := False;
                        MemoLog.Lines.Add('...2.Disconnect');
                        end;

                        end.
                        </pre>
                        DFM:
                        <pre>
                        object Form1: TForm1
                        Left = 286
                        Top = 107
                        Width = 386
                        Height = 480
                        Caption = 'SIBProviderTest'
                        Color = clBtnFace
                        Font.Charset = DEFAULT_CHARSET
                        Font.Color = clWindowText
                        Font.Height = -11
                        Font.Name = 'MS Sans Serif'
                        Font.Style = []
                        OldCreateOrder = False
                        PixelsPerInch = 96
                        TextHeight = 13
                        object DBGrid1: TDBGrid
                        Left = 120
                        Top = 40
                        Width = 241
                        Height = 65
                        DataSource = DataSourceMain
                        TabOrder = 0
                        TitleFont.Charset = DEFAULT_CHARSET
                        TitleFont.Color = clWindowText
                        TitleFont.Height = -11
                        TitleFont.Name = 'MS Sans Serif'
                        TitleFont.Style = []
                        end
                        object DBNavigator1: TDBNavigator
                        Left = 120
                        Top = 16
                        Width = 240
                        Height = 25
                        DataSource = DataSourceMain
                        TabOrder = 1
                        end
                        object MemoLog: TMemo
                        Left = 0
                        Top = 232
                        Width = 378
                        Height = 221
                        Align = alBottom
                        Lines.Strings = (
                        )
                        TabOrder = 2
                        end
                        object ButtonOpen: TButton
                        Left = 120
                        Top = 112
                        Width = 75
                        Height = 25
                        Caption = 'ButtonOpen'
                        TabOrder = 3
                        OnClick = ButtonOpenClick
                        end
                        object ButtonClose: TButton
                        Left = 232
                        Top = 112
                        Width = 75
                        Height = 25
                        Caption = 'ButtonClose'
                        TabOrder = 4
                        OnClick = ButtonCloseClick
                        end
                        object ButtonTest: TButton
                        Left = 120
                        Top = 152
                        Width = 75
                        Height = 25
                        Caption = 'ButtonTest'
                        TabOrder = 5
                        OnClick = ButtonTestClick
                        end
                        object ADOConnectionMain: TADOConnection
                        ConnectionString =
                        'Provider=sibprovi.SIBProvider;Password=masterkey; User ID=SYSDBA;' +
                        'Data Source=C:\Database\SIBProv.gdb;Location=localhost: ;Extended' +
                        ' Properties="";Persist Encrypted=True;Encrypt Password=True;Mask' +
                        ' Password=True;Cache Authentication=True;Persist Security Info=T' +
                        'rue;CHARACTER SET="";ROLE=""'
                        IsolationLevel = ilReadCommitted
                        LoginPrompt = False
                        Provider = 'sibprovi.SIBProvider'
                        Left = 24
                        Top = 16
                        end
                        object ADOConnectionLastValue: TADOConnection
                        Connected = True
                        ConnectionString =
                        'Provider=sibprovi.SIBProvider;Password=masterkey; User ID=SYSDBA;' +
                        'Data Source=C:\Database\SIBProv.gdb;Location=localhost: ;Extended' +
                        ' Properties="";Persist Encrypted=True;Encrypt Password=True;Mask' +
                        ' Password=True;Cache Authentication=True;Persist Security Info=T' +
                        'rue;CHARACTER SET="";ROLE=""'
                        CursorLocation = clUseServer
                        LoginPrompt = False
                        Provider = 'sibprovi.SIBProvider'
                        Left = 24
                        Top = 152
                        end
                        object ADODataSetMain: TADODataSet
                        Connection = ADOConnectionMain
                        CursorType = ctStatic
                        CommandText = 'select ID, WERT, INFO from TESTTBL'
                        Parameters = <>
                        Left = 56
                        Top = 16
                        object ADODataSetMainID: TIntegerField
                        FieldName = 'ID'
                        end
                        object ADODataSetMainWERT: TIntegerField
                        FieldName = 'WERT'
                        end
                        object ADODataSetMainINFO: TStringField
                        FieldName = 'INFO'
                        Size = 11
                        end
                        end
                        object DataSourceMain: TDataSource
                        DataSet = ADODataSetMain
                        Left = 88
                        Top = 16
                        end
                        object ADODataSetLastValue: TADODataSet
                        Active = True
                        Connection = ADOConnectionLastValue
                        CursorType = ctStatic
                        CommandText = 'select WERT from LASTVALUE'
                        Parameters = <>
                        Left = 56
                        Top = 152
                        object ADODataSetLastValueWERT: TIntegerField
                        FieldName = 'WERT'
                        end
                        end
                        end
                        </pre&gt

                        Comment


                        • #13
                          Danke Andreas, werde mich mal damit auseinandersetzen.

                          Gruß Elk

                          Comment


                          • #14
                            Hallo Andreas,

                            endlich hab ich die lang ersehnte Lösung gefunden und wie so oft war sie ganz einfach.

                            Scheinbar wurde die StoredProcedure nicht wie gewollt bei jedem aktivieren bzw. Einfügen eines neuen Datensatzes wieder ausgeführt, sondern es wurde einfach das Ergebnis des ersten Aufrufes wieder zurückgegeben. Einen neuen Aufruf der Procedure habe ich dadurch erreicht, dass ich bei jedem Click auf die CheckBox erst einmal StoredProc.active := false und dann wieder auf true gesetzt habe. Jetzt wird jedesmal die Procedur erneut aufgerufen und ich erhalte die Werte, wie sie sein sollen.

                            Zum Glück liegt es also nicht am Provider. Mit dem scheint bisher alles gut zu funktionieren. Also Danke noch mal für die vielen Anregungen.

                            Gruß Elk

                            Comment

                            Working...
                            X