Freigeben über


Aktualisieren von Daten

Zum Aktualisieren von Daten können Sie Zwischenspeicher, Transaktionen oder Ansichten verwenden.

Aktualisieren mit Hilfe der Zwischenspeicherfunktion

Nach Auswahl der gewünschten Zwischenspeichermethode und des Sperrungstyps können Sie die Datensatz- oder Tabellenpufferung aktivieren.

So aktivieren Sie die Zwischenspeicherung

Wählen Sie eine der folgenden Optionen:

  • Legen Sie im Formular-Designer die BufferModeOverride-Eigenschaft des Cursors in der Datenumgebung des Formulars fest.

    - Oder -

  • Legen Sie die Buffering-Eigenschaft fest, wenn Sie mit Code arbeiten.

    Sie können beispielsweise die pessimistische Zeilenpufferung aktivieren, indem Sie den folgenden Code in die Init-Prozedur eines Formulars einbinden:

    CURSORSETPROP('Buffering', 2)
    

Anschließend binden Sie den Code für die Aktualisierungsoperationen in den entsprechenden Methodencode Ihrer Steuerelemente ein.

Um Bearbeitungen in die Originaltabelle zu schreiben, verwenden Sie TABLEUPDATE( ). Um Bearbeitungen nach einer fehlgeschlagenen Aktualisierungsoperation in einer von Gültigkeitsregeln beschränkten Tabelle abzubrechen, verwenden Sie TABLEREVERT( ). TABLEREVERT( ) ist auch dann gültig, wenn die explizite Tabellenpufferung nicht aktiviert ist.

Im folgenden Beispiel wird demonstriert, wie Datensätze aktualisiert werden, wenn die pessimistische Datensatzpufferung aktiviert ist.

Beispiel für das Aktualisieren unter Verwendung von Datensatz- und Tabellenpuffern

Code Kommentar
OPEN DATABASE testdata
USE customers
CURSORSETPROP('Buffering', 2)         
Öffnet als Bestandteil des Init-Codes des Formulars die Tabelle und aktiviert die pessimistische Datensatzpufferung.
lModified = .F.
FOR nFieldNum = 1 TO FCOUNT()         
   IF GETFLDSTATE(nFieldNum) = 2      
      lModified = .T.
      EXIT
   ENDIF
ENDFOR

Prüft, ob Felder geändert wurden.

Anmerkung   Dieser Code könnte in das Click-Ereignis der Befehlsschaltfläche Speichern oder Aktualisieren eingebunden sein.

IF lModified
   nResult = MESSAGEBOX;
      ("Record has been modified. Save?", ;
      4+32+256, "Data Change")
Sucht den nächsten geänderten Datensatz.
   IF nResult = 7                  
      TABLEREVERT (.F.)            
   ENDIF
ENDIF
Präsentiert den aktuellen Wert und gibt dem Benutzer die Möglichkeit, die Änderung im aktuellen Feld rückgängig zu machen.
SKIP                           
IF EOF()
   MESSAGEBOX( "already at bottom")
   SKIP -1
ENDIF 
THISFORM.Refresh



SKIP gewährleistet, dass die letzte Änderung geschrieben wird.

Verwalten von Aktualisierungen mit Transaktionen

Auch bei der Zwischenspeicherung verläuft nicht immer alles problemlos. Wenn Sie Aktualisierungsoperationen schützen und die Auswirkungen eines gesamten Codeabschnitts als Einheit rückgängig machen möchten, sollten Sie Transaktionen verwenden.

Das Hinzufügen von Transaktionen zu Ihrer Anwendung bietet Schutz über die Visual FoxPro-Datensatz- und -Tabellenpufferung hinaus, indem ein gesamter Codeabschnitt in einer geschützten, wiederherstellbaren Einheit platziert wird. Sie können Transaktionen verschachteln und diese zum Schutz von zwischengespeicherten Aktualisierungen verwenden. Visual FoxPro-Transaktionen stehen nur im Zusammenhang mit Tabellen und Ansichten zur Verfügung, die in einer Datenbank enthalten sind.

Zusammenfassen von Codesegmenten zu einer Einheit

Eine Transaktion dient als eine Hülle, in der Datenaktualisierungsoperationen im Arbeitsspeicher oder auf der Festplatte zwischengespeichert werden, anstatt diese direkt an die Datenbank weiterzugeben. Die tatsächliche Datenbankaktualisierung wird erst am Ende der Transaktion vorgenommen. Sollte das System aus irgendeinem Grund die Aktualisierungsoperation an der Datenbank nicht durchführen können, können Sie die gesamte Transaktion rückgängig machen, und es werden keine Aktualisierungen durchgeführt.

Anmerkung   Zwischengespeicherte Aktualisierungsoperationen, die außerhalb einer Transaktion vorgenommen wurden, werden innerhalb einer Transaktion im Verlauf der gleichen Datensitzung ignoriert.

Befehle zum Steuern von Transaktionen

Visual FoxPro unterstützt drei Befehle und eine Funktion zum Verwalten einer Transaktion.

Aufgabenstellung Verknüpfungsart
Initiieren einer Transaktion BEGIN TRANSACTION
Bestimmen der aktuellen Transaktionsebene TXNLEVEL( )
Rückgängigmachen aller seit der jüngsten BEGIN TRANSACTION-Anweisung vorgenommenen Änderungen ROLLBACK
Sperren der Datensätze, Übergeben aller seit der jüngsten BEGIN TRANSACTION-Anweisung vorgenommenen Änderungen an Tabellen in der Datenbank und Freigeben der Datensätze END TRANSACTION

Sie können mit Transaktionen Änderungen an Tabellen, strukturellen CDX-Dateien und Memodateien, die mit Tabellen in einer Datenbank verbunden sind, umhüllen. Von Operationen, die Variablen oder andere Objekte involvieren, werden Transaktionen nicht berücksichtigt. Daher können Sie solche Operationen weder rückgängig machen noch übergeben.

Anmerkung   Bei Verwendung von Daten, die in Remotetabellen gespeichert sind, steuern die Transaktionsbefehle nur die Aktualisierung der Daten in der lokalen Kopie des Cursors der Ansicht. Aktualisierungen an Remotebasistabellen werden nicht beeinflusst. Um manuelle Transaktionen an Remotetabellen zu ermöglichen, verwenden Sie SQLSETPROP( ), und steuern Sie nun die Transaktion mit SQLCOMMIT( ) und SQLROLLBACK( ).

Im Allgemeinen sollten Sie Transaktionen eher mit Datensatzpuffern als mit Tabellenpuffern verwenden, es sei denn, Sie möchten TABLEUPDATE( )-Aufrufe umhüllen. Wenn Sie den TABLEUPDATE( )-Befehl in einer Transaktion verwenden, können Sie eine fehlgeschlagene Aktualisierung rückgängig machen, den Grund für den Fehlschlag ausfindig machen und den TABLEUPDATE( )-Befehl wiederholen, ohne dass es zu einem Datenverlust kommt. Hiermit wird sichergestellt, dass die Aktualisierung als "Alles-oder-Nichts"-Operation vorgenommen wird.

Obwohl die einfache Transaktionsverarbeitung normalerweise ausreichend Sicherheit bei Aktualisierungsoperationen bietet, kann hiermit kein allumfassender Schutz gegen Systemausfälle gewährleistet werden. Bei einem Stromausfall oder wenn es während der Verarbeitung des END TRANSACTION-Befehls zu einer anderen Art der Systemunterbrechung kommt, kann die Datenaktualisierung immer noch fehlschlagen.

Verwenden Sie die folgende Codevorlage für Transaktionen:

BEGIN TRANSACTION   
* Update records
IF lSuccess = .F. && an error occurs
   ROLLBACK
ELSE && commit the changes
   * Validate the data
   IF && error occurs
      ROLLBACK
   ELSE 
      END TRANSACTION
   ENDIF
ENDIF

Verwenden von Transaktionen

Bei Transaktionen gelten die folgenden Regeln:

  • Eine Transaktion beginnt mit dem BEGIN TRANSACTION-Befehl und endet mit dem END TRANSACTION- oder ROLLBACK-Befehl. Eine END TRANSACTION-Anweisung ohne vorangegangene BEGIN TRANSACTION-Anweisung führt zur Erzeugung einer Fehlermeldung.
  • Eine ROLLBACK-Anweisung ohne vorangegangene BEGIN TRANSACTION-Anweisung führt zur Erzeugung einer Fehlermeldung.
  • Eine einmal begonnene Transaktion bleibt so lange wirksam, bis die entsprechende END TRANSACTION-Anweisung beginnt (oder ein ROLLBACK-Befehl ausgeführt wird) - sogar über Programme und Funktionen hinaus - es sei denn, die Anwendung wird beendet, wodurch ein Zurücksetzen verursacht wird.
  • Visual FoxPro verwendet für die Abfrage von Daten, die in Transaktionen involviert sind, zunächst die im Transaktionspuffer gespeicherten Daten bevor auf Daten der Festplatte zugegriffen wird. Hiermit wird sichergestellt, dass immer die aktuellsten Daten verwendet werden.
  • Wenn die Anwendung während einer Transaktion beendet wird, werden alle Operationen zurückgesetzt.
  • Eine Transaktion kann nur in einem Datenbank-Container stattfinden.
  • Sie können den INDEX-Befehl nicht verwenden, wenn hierdurch eine bestehende Indexdatei überschrieben würde oder wenn eine beliebige CDX-Indexdatei geöffnet ist.
  • Transaktionen sind in ihrer Gültigkeit auf Datensitzungen beschränkt.

Transaktionen zeigen beim Sperren die folgenden Verhaltensweisen:

  • Innerhalb einer Transaktion setzt Visual FoxPro zu dem Zeitpunkt eine Sperrung, zu dem ein Befehl direkt oder indirekt dazu auffordert. Alle vom System oder dem Benutzer initiierten direkten oder indirekten Befehle zum Aufheben der Sperrung werden zwischengespeichert, bis die Transaktion mit den Befehlen ROLLBACK oder END TRANSACTION beendet wird.
  • Wenn Sie innerhalb einer Transaktion einen Sperrbefehl wie FLOCK( ) oder RLOCK( ) verwenden, wird die Sperrung mit der END TRANSACTION-Anweisung nicht aufgehoben. In einem solchen Fall müssen Sie alle Sperrungen, die innerhalb einer Transaktion vorgenommen wurden, explizit aufheben. Darüber hinaus sollten Sie Transaktionen, die einen der Befehle FLOCK( ) oder RLOCK( ) enthalten, so kurz wie möglich halten. Andernfalls könnten andere Benutzer für lange Zeit vom Zugriff auf Datensätze ausgeschlossen sein.

Verschachteln von Transaktionen

Mit verschachtelten Transaktionen erhalten Sie logische Gruppen von Tabellenaktualisierungsoperationen, die so von gleichzeitig ablaufenden Prozessen isoliert sind. BEGIN TRANSACTION...END TRANSACTION-Paare müssen sich nicht in der gleichen Funktion oder Prozedur befinden. Bei verschachtelten Transaktionen gelten die folgenden Regeln:

  • Sie können bis zu fünf BEGIN TRANSACTION...END TRANSACTION-Paare verschachteln.
  • Aktualisierungen, die in einer verschachtelten Transaktion vorgenommen werden, werden erst übergeben, nachdem die am weitesten außen befindliche END TRANSACTION-Anweisung aufgerufen wurde.
  • In verschachtelten Transaktionen wirkt eine END TRANSACTION-Anweisung nur auf die von der zuletzt ausgegebenen BEGIN TRANSACTION-Anweisung initiierten Transaktion.
  • In verschachtelten Transaktionen wirkt eine ROLLBACK-Anweisung nur auf die von der zuletzt ausgegebenen BEGIN TRANSACTION-Anweisung initiierten Transaktion.
  • Die in einer Gruppe von verschachtelten, die gleichen Daten betreffenden Transaktionen am weitesten innen befindliche Aktualisierung hat Vorrang vor allen anderen in der gleichen Gruppe verschachtelter Transaktionen.

Beachten Sie im nachstehenden Beispiel, dass aufgrund der Tatsache, dass Änderungen in einer verschachtelten Transaktion nicht auf die Festplatte, sondern in den Transaktionspuffer geschrieben werden, die innere Transaktion die Änderungen überschreibt, die an den gleichen Feldern mit Namen STATUS in früheren Transaktionen vorgenommen wurden:

BEGIN TRANSACTION &&  transaction 1
   UPDATE EMPLOYEE ; &&  first change
      SET STATUS = "Contract" ;
      WHERE EMPID BETWEEN 9001 AND 10000
   BEGIN TRANSACTION &&  transaction 2
      UPDATE EMPLOYEE ;
         SET STATUS = "Exempt" ;
         WHERE HIREDATE > {^1998-01-01}  &&  overwrites
   END TRANSACTION &&  transaction 2
END TRANSACTION    &&  transaction 1

Im folgenden Beispiel für eine verschachtelte Transaktion werden ein Kundendatensatz sowie alle hiermit zusammenhängenden Rechnungen gelöscht. Die Transaktion wird zurückgesetzt, wenn bei der Abarbeitung des DELETE-Befehls Fehler auftreten. Dieses Beispiel demonstriert das Gruppieren von Tabellenaktualisierungsoperationen zum Schutz der Aktualisierungen vor partieller Beendigung und zum Vermeiden von Konflikten mit gleichzeitig ablaufenden Prozessen.

Beispiel für das Modifizieren von Datensätzen in verschachtelten Transaktionen

Code Kommentar
DO WHILE TXNLEVEL( ) > 0
   ROLLBACK
ENDDO
Abschlussprozedur von anderen Transaktionen.
CLOSE ALL
SET MULTILOCKS ON
SET EXCLUSIVE OFF
Richtet die Umgebung für Zwischenspeicherung ein.
OPEN DATABASE test
USE mrgtest1
CURSORSETPROP('buffering',5)
GO TOP


Aktiviert die optimistische Tabellenpufferung.
REPLACE fld1 WITH "changed"
SKIP
REPLACE fld1 WITH "another change"
MESSAGEBOX("modify first field of both" + ;
   "records on another machine")
Ändert einen Datensatz.

Ändert einen weiteren Datensatz.
BEGIN TRANSACTION
lSuccess = TABLEUPDATE(.T.,.F.)
Startet Transaktion 1 und versucht, alle geänderten Datensätze zu aktualisieren, ohne dies zu erzwingen.
IF lSuccess = .F.
   ROLLBACK
   AERROR(aErrors)
   DO CASE 
   CASE aErrors[1,1] = 1539            
   ...
   CASE aErrors[1,1] = 1581            
   ...
   CASE aErrors[1,1] = 1582            
Falls Aktualisierung fehlschlägt, wird die Transaktion rückgängig gemacht.
Auslesen des Fehlers aus AERROR( ).
Ermittelt die Fehlerursache.
Falls ein Trigger fehlgeschlagen ist, Fehlerbehandlung aktivieren.

Falls ein Feld keine Nullwerte akzeptiert, Fehlerbehandlung aktivieren.
Falls eine Feldregel verletzt wurde, Fehlerbehandlung aktivieren.
   CASE aErrors[1,1] = 1585            
      nNextModified = getnextmodified(0)
      DO WHILE nNextModified <> 0
         GO nNextModified
         RLOCK()
         FOR nField = 1 to FCOUNT()
            cField = FIELD(nField)
            if OLDVAL(cField) <> CURVAL(cField)
Falls der Datensatz bereits von einem anderen Benutzer geändert wurde, ersten geänderten Datensatz suchen.
Schleifendurchlauf durch alle geänderten Datensätze, und zwar beginnend beim ersten Datensatz.
Jeden Datensatz sperren, um sicherzustellen, dass aktualisiert werden kann.
Alle Felder auf Änderungen prüfen.

Zwischengespeicherten Wert mit dem Wert auf Festplatte vergleichen und anschließend ein Dialogfeld für den Benutzer aufrufen.
               nResult = MESSAGEBOX;
               ("Data was changed " + ;
                "by another user — keep"+ ;
                "changes?", 4+48, ;
                "Modified Record")
 
               IF nResult = 7
                  TABLEREVERT(.F.)
                  UNLOCK record nNextModified
               ENDIF
Falls der Benutzer mit "Nein" antwortet, diesen Datensatz zurücksetzen und Sperre aufheben.
               EXIT
            ENDIF
         ENDFOR
FOR nField...-Schleife unterbrechen.
      ENDDO
Den nächsten geänderten Datensatz auslesen.
      BEGIN TRANSACTION
      TABLEUPDATE(.T.,.T.)
      END TRANSACTION
      UNLOCK
Startet Transaktion 2 und erzwingt die Aktualisierung aller nicht zurückgesetzter Datensätze.
Beendet Transaktion 2.
Hebt die Sperre auf.
   CASE aErrors[1,1] = 109   
   ...
   CASE aErrors[1,1] = 1583    
   ...
   CASE aErrors[1,1] = 1884    
   ...
   OTHERWISE
      MESSAGEBOX( "Unknown error "+;
      "message: " + STR(aErrors[1,1]))
   ENDCASE
Falls Datensatz aktuell von anderem Benutzer verwendet wird, Fehlerbehandlung aktivieren.

Falls eine Zeilenregel verletzt wurde, Fehlerbehandlung aktivieren.

Falls ein eindeutiger Index verletzt wurde, Fehlerbehandlung aktivieren.

Andernfalls wird ein Dialogfeld für den Benutzer aufgerufen.
ELSE
   END TRANSACTION
ENDIF

Ende von Transaktion 1.

Schützen von Remoteaktualisierungen

Transaktionen können als Schutz vor vom System erzeugten Fehlern bei der Datenaktualisierung in Remotetabellen dienen. Im folgenden Beispiel wird eine Transaktion zum Umhüllen einer Datenschreiboperation in eine Remotetabelle verwendet.

Beispiel für eine Transaktion betreffend eine Remotetabelle

Code Kommentar
hConnect = CURSORGETPROP('connecthandle')
SQLSETPROP(hConnect, 'transmode',
DB_TRANSMANUAL)
Ermittelt das Verbindungshandle und ermöglicht manuelle Transaktionen.
BEGIN TRANSACTION
Startet die manuelle Transaktion.
lSuccess = TABLEUPDATE(.T.,.F.)
IF lSuccess = .F.
   SQLROLLBACK (hConnect)
   ROLLBACK
Versucht, alle Datensätze zu aktualisieren, ohne dies zu erzwingen.
Falls die Aktualisierung fehlschlägt, wird die Transaktion über die Verbindung für den Cursor zurückgesetzt.
   AERROR(aErrors)
   DO CASE 
Auslesen des Fehlers aus AERROR( ).
   CASE aErrors[1,1] = 1539            
   ...
Falls ein Trigger fehlgeschlagen ist, Fehlerbehandlung aktivieren.
   CASE aErrors[1,1] = 1581            
   ...
Falls ein Feld keine Nullwerte akzeptiert, Fehlerbehandlung aktivieren.
   CASE aErrors[1,1] = 1582            
   ...
Falls eine Feldregel verletzt wurde, Fehlerbehandlung aktivieren.
   CASE aErrors[1,1] = 1585            
      nNextModified = GETNEXTMODIFIED(0)
      DO WHILE nNextModified <> 0
         GO nNextModified
Falls der Datensatz bereits von einem anderen Benutzer geändert wurde, Fehlerbehandlung aktivieren.

Schleifendurchlauf durch alle geänderten Datensätze, und zwar beginnend beim ersten Datensatz.
         FOR nField = 1 to FCOUNT()
            cField = FIELD(nField)
            IF OLDVAL(cField) <> CURVAL(cField)
               nResult = MESSAGEBOX;
               ("Data has been changed ;
               by another user. ;
               Keep changes?",4+48,;
               "Modified Record")
Alle Felder auf Änderungen prüfen.

Zwischengespeicherte Werte mit dem Wert auf Festplatte vergleichen und anschließend ein Dialogfeld für den Benutzer aufrufen.
               IF nResult = 7
                  TABLEREVERT(.F.)
               ENDIF
               EXIT
            ENDIF
         ENDFOR
         nNextModified = ;
         GETNEXTMODIFIED(nNextModified)
      ENDDO
Wenn Benutzer mit "Nein" antwortet, diesen Datensatz zurücksetzen.

FOR nField...-Schleife unterbrechen.


Den nächsten geänderten Datensatz auslesen.
      TABLEUPDATE(.T.,.T.)
      SQLCOMMIT(hConnect)
Erzwingt die Aktualisierung aller nicht zurückgesetzter Datensätze und veranlasst eine Übergabe.
   CASE aErrors[1,1] = 109
         * Handle the error
Fehler 109 zeigt an, dass der Datensatz aktuell von einem anderen Benutzer verwendet wird.
   CASE aErrors[1,1] = 1583
         * Handle the error
Fehler 1583 zeigt an, dass eine Zeilenregel verletzt wurde.
   CASE aErrors[1,1] = 1884
         * Handle the error
Fehler 1884 zeigt an, dass die Eindeutigkeit eines Indexes verletzt wurde.
   OTHERWISE
         * Handle generic errors.
 
      MESSAGEBOX("Unknown error message:" ;
        + STR(aErrors[1,1]))
   ENDCASE
Ruft ein Dialogfeld für den Benutzer auf.

Ende der Fehlerbehandlung.
ELSE
   SQLCOMMIT(hConnect)
   END TRANSACTION
ENDIF

Falls alle Fehler behandelt wurden und die gesamte Transaktion erfolgreich abgeschlossen ist, Übergabe veranlassen und Transaktion beenden.

Siehe auch

Zwischenspeichern von Daten | Verwalten der Leistung | Programmieren für freigegebenen Zugriff | TABLEUPDATE( ) | TABLEREVERT( ) | Steuern des Zugriffs auf Daten | Konfliktverwaltung