Announcement

Collapse
No announcement yet.

Kollision mit einer Transaktion - SQL Server 7.0

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

  • Kollision mit einer Transaktion - SQL Server 7.0

    Hallo,

    habe da ein großes Problem. Ich arbeite mit dem Isolationslevel ReadCommitted (SQL Server 7). Wenn das Clientprogramm auf einen Datensatz trifft, der bereits durch eine Transaktion verarbeitet wird, bleibt das ganze Programm stehen. Es entsteht nun eine Situation die sehr schlecht für den Anwender ist. (In solchen fällen klickt der Anwender auf alles was er findet. )

    Besteht die Möglichkeit auf solch ein Ereignis zu reagieren, App’s die einfach so stehen bleiben ohne die Sanduhr oder sonstiges anzuzeigen, machen nicht gerade einen stabilen Eindruck.

    Bis dann
    Mathias

  • #2
    Hallo,

    beim SQL Server 7 ist es in 99% der Fälle sinnvoll, mit einem Client-side-Recordset (CursorLocation = <b>clUseClient</b>) zu arbeiten. Wenn man einen Mehrbenutzerzugriff mit mehreren Programminstanzen auf den gleichen Datensatz mit dem folgenden Beispielprojekt simuliert, tritt dieses Problem nicht auf:
    <pre>
    object ADOConnection1: TADOConnection
    ConnectionString =
    'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initi' +
    'al Catalog=IBImport;Data Source=(local)'
    IsolationLevel = ilReadCommitted
    LoginPrompt = False
    Provider = 'SQLOLEDB.1'
    Left = 8
    Top = 16
    end
    object ADODataSet1: TADODataSet
    Connection = ADOConnection1
    CursorType = ctStatic
    CommandText = 'ORTE'
    CommandType = cmdTableDirect
    Parameters = <>
    Left = 48
    Top = 16
    end
    </pre>
    Der zweite Client erhält beim Versuch, den gleichen Datensatz zu speichern die Fehlermeldung "<i>Die zum Aktualisieren angegeben Zeile wurde nicht gefunden. Einige Werte wurden seit dem letzten Lesen eventuell geändert</i>". Das Programm hängt nicht - sondern liefert sofort eine Fehlermeldung zurück.

    Wenn man allerdings auf einen Server-side-Cursor (<b>clUseServer</b>) zurückgreift, ändert sich das Verhalten:
    <pre>
    object ADOConnection1: TADOConnection
    ConnectionString =
    'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initi' +
    'al Catalog=IBImport;Data Source=(local)'
    CursorLocation = clUseServer
    IsolationLevel = ilReadCommitted
    LoginPrompt = False
    Provider = 'SQLOLEDB.1'
    Left = 8
    Top = 16
    end
    object ADODataSet1: TADODataSet
    Connection = ADOConnection1
    CursorLocation = clUseServer
    CursorType = ctDynamic
    CommandText = 'ORTE'
    CommandType = cmdTableDirect
    Parameters = <>
    Left = 48
    Top = 16
    object ADODataSet1ORTID: TIntegerField
    FieldName = 'ORTID'
    end
    object ADODataSet1PLZ: TStringField
    FieldName = 'PLZ'
    Size = 5
    end
    object ADODataSet1ORT: TStringField
    FieldName = 'ORT'
    Size = 25
    end
    end
    </pre>
    Arbeitet man dann die folgenden Schritte ab, muss der 2. Client warten, bis der erste Client den Schritt c) durchführt: <br>
    a) ADOConnection1.BeginTrans; <br>
    b) Datensatz editieren, posten und warten <br>
    c) ADOConnection1.CommitTrans;<br>
    In diesem Fall muss man als Entwickler dafür sorgen, dass der Benutzer niemals die Zeitdauer einer aktivien Transaktion bestimmen darf und dass die Transaktionen nur einen kurzen Zeitraum aktiv sind.
    &#10

    Comment


    • #3
      Hallo Andreas,

      mmmh komisch, setzte jetzt auch die CSC (Client Cursor) ein. Habe vor ein paar Tagen mal gefragt wie, was bei den Settings (MSSQL 7)bei ADOConn zu beachten ist. Alle die geantwortet haben, sprachen von der Cursor Lokalisation ClientSite. Habe es dann auch bei meinen DataSets eingestellt. Bei AdoConn war ich nicht sicher, habe ServerSite stehen lassen.

      Ich es gleich mal probieren, das wäre ja auch furchtbar gewesen, wenn sich der Client gnadenlos verabschiedet.

      !!!
      Es hat sich nichts geändert, der Client bleibt immer noch stehen. Habe hier NT Server 4.0 SqlServer 7.0 SP2 und Delphi5 Pro mit AdoExpress. Ist das ausreichend oder braucht man die Enterprise Version von Delphi ? Ich habe gesehten das du nicht auf einem Server arbeitest, sondern mit DataSource (local) ProviderSittings. Da gibt es doch sicherlich unterschiede, ich fahre den SQL Server auf einen NT Server und auf den Clients wird entwickelt, muss ich da noch irgendwas besonderes beachten ?

      Bis dann
      Mathia

      Comment


      • #4
        Hallo,

        mein Eintrag "(local)" bedeutet nichts anderes, als dass der SQL Server 7 SP2 auf meinem Entwicklungsrechner läuft. Ich würde mir die Konfiguration von TADOConnection und TADODataSet genauer anschauen (rechter Mausklick -> Anzeigen als Text). Werden dort auch die Einträge angezeigt, die in meiner Antwort aufgeführt wurden?

        Es sollte keine Rolle spielen, ob die Professional- oder die Enterprise-Version von Delphi 5 eingesetzt wird, vorausgesetzt, man hat: <br>
        a) das <b>UpdatePack#1</b> von Delphi 5 eingespielt, und <br>
        b) das <b>ADO-Patch Oktober 2000</b> von CodeCentral heruntergeladen und eingespielt.
        &#10

        Comment


        • #5
          Hallo Andreas,

          na das is ja nen Ding, bei mir stand da ne Menge drin, muss wohl der conn builder gemacht haben. Habe alles entfernt, bis auf Deine Zeilen. Und jetzt blockiert nichts mehr, läuft tadellos.. mmhhh
          Sogar mir der besagten Meldung....

          Hast Du da vieleicht noch ein paar Connection Strings, für mein Doko - Archiv, wo hast Du die Dinge blos her. Wollte schon fast auf ein anders Database System gehen, doppelt verkette listen in Speicher, absolut Transaktionsfrei

          Danke mann, mir ist nen riesen Stein vom Herzen gefallen.
          Puhhh.... Mathias (noch mal Schwein gehabt :

          Comment


          • #6
            Hallo Andreas,

            es hat nur einmal funktioniert, und jetzt habe ich wieder die gleichen Problem. Nach dem Connect erweitert ADO den ConnectionString. Habe dann den String zur Laufzeit generiert, nach dem Connect wird auch dieser wieder erweitert. Wenn Client1 auf einen Datensatz trifft der bereits von einer Client2 - Transaktion verarbeitet wird, bleibt Client1 solange stehen bis Client2 die Transaktion beendet hat.

            Kannst Du mir bitte nochmal helfen, Transaktionen sind für die App sehr wichtig, andere Clients dürfen auf keinen Fall einfach so stehen bleiben.

            Als es funktionierte, hatte ich den Profiler und Analyser aktiv, um das ganze zu beobachten, hatte auch mit SET Explicit_Transaction ON/OFF ein wenig getestet. Ich habe einfach zu wenig Erfahrungen, vieleicht kann ja auch am SQL Server was eingestellt werden.

            Bis dann
            Mathia

            Comment


            • #7
              Hallo,

              wenn du vor dem Post eine Abfrage am SQL-Server ausführst und versuchst diesen Datensatz exclusiv zu sperren (mit kleinem Timeout 1-2 Sek max.) erhälst du eine Fehlermeldung zurück das der Server den Satz nicht exclusiv sperren konnte. Wenn du das ganze in einer Transaktion kapselst kannst du wenn die funktion true zurückgibt, der Satz konnte gesperrt werden anschliessend dein Post ausführen und dann die Transaktion freigeben.

              Also s. ä.

              ADOConn.BeginTrans;

              SET LOCK_TIMEOUT 1000 --1 Sekunde
              SELECT ID FROM Tabelle WITH (UPDLOCK) WHERE ID = :ID

              Wenn die Abfrage keine Exception schmeisst, dann kannst du denn
              Datensatz ändern.

              ADODS.POST;
              ADOCONN.CommitTrans;

              So ungefährt müsste es gehen. Ich hab denn Code aus meiner App wieder entfernt da ich mit Optimistischem Sperrverhalten Arbeite und bei Tabellen in denen der Anwender viel ändern kann (Adressen ..) eine StoredProc zum speichern nehmen die eine Aktualiesierungabfrage durchführt nach den Feldern die der Anwender geändert hat.

              Ich hoffe du kannst damit was Anfangen :

              Comment


              • #8
                Hi Stefan,

                ja Danke für die Infos, aber so langsam muss man sich Fragen, ob sich solch ein Aufwand loht. Wenn es schon bei grundlegenden Dingen Probleme gibt, was soll das erst bei richtigen Problemen werden.

                Ja die Geschichte mit dem Lock_Timeout, da ging ja gleich ein Lämpchen an. Das hätte mir völlig ausgereicht um meine App aus dem Stillstand zu bewegen.

                Aber das Lämpchen brannte sehr schnell durch, der Query Analyser reagiert ja wunderbar auf das eingestellte TimeOut. Bei ADO sieht das mal wieder völlig anders aus, im Profiler wurde das Ereignis angezeigt, der Wert wurde von der ADO - App gesendet, aber die ADO -App reagiert selbst nicht auf das TimeOut, die App hängt jetzt immmer noch in der Uhr. Ich weis auch nicht, mann wir haben jetzt 2001, ich komme mir vor wie im alten Rom. Wahrscheinlich steht ADO für "Allgemeiner Datenbank Optimismus". Ich könnte schon wieder was aus dem Fenster schmeißen.

                Nee.... Nee... Nee... Was hier wieder los ist. Na ja, die Rechner können ja nichts dafür.

                Vieleicht sollte ich meien Usern mal den Query Analyer vorstellen. Wozu braucht man heut zu Tage schon einen Client, lasst die Leute doch gleich am Server arbeiten, da wird es dann wahrscheinlich nie langweilig werdem

                Bis denne
                Mathia

                Comment


                • #9
                  Hallo,

                  wer wird denn gleich in die Luft gehen ;-)

                  Wenn ein Entwickler auf die bequemen ADO-Objekte zurückgreift, um sich die Arbeit zu erleichtern, bedeutet dies auch, dass sich der Entwickler an die ADO-Regeln halten muss (und nicht umgekehrt). Die Diskussion erinnert mich etwas an die lustige Geschichte mit der amerikanischen Hausfrau, ihrer Katze und der Mikrowelle. Wenn man die Katze in die Mikrowelle steckt, um das Tier nach dem Baden zu trocken, darf man sich nicht wundern, wenn am Ende keine liebe Katze mehr rauskommt ;-)

                  Mit ADO kann man eine Stapelanweisung (die aus mehreren T-SQL-Aufrufen besteht) abschicken - daher kann ADO genausoviel wie der Query Analyzer.

                  In der Hilfe zum SQL Server 7 steht der folgende Satz: "<i>Der Microsoft OLE DB-Provider für SQL Server und der ODBC-Treiber von SQL Server stellen beim Herstellen einer Verbindung IMPLICIT_TRANSACTIONS automatisch auf OFF ein. SET IMPLICIT_TRANSACTIONS wird für Verbindungen von DB-Library-Anwendungen standardmäßig auf OFF eingestellt. Ist SET ANSI_DEFAULTS auf ON eingestellt, so ist SET IMPLICIT_TRANSACTIONS aktiviert.</i>".

                  Da ebenfalls die Aussage aus dem MDAC-SDK "<i>The SQL Server ODBC driver and Microsoft OLE DB Provider for SQL Server automatically set ANSI_DEFAULTS to ON when connecting.</i>" gilt, ist damit auch SET IMPLICIT_TRANSACTIONS automatisch auf ON eingestellt.

                  &#10

                  Comment

                  Working...
                  X