Freigeben über


Simulieren von positionierten Aktualisierungen und DELETE-Anweisungen

Wenn die Datenquelle keine positionierten Aktualisierungs- und Löschanweisungen unterstützt, kann der Treiber diese simulieren. Beispielsweise simuliert die ODBC-Cursorbibliothek positionierte Aktualisierungs- und Löschanweisungen. Die allgemeine Strategie zum Simulieren positionierter Aktualisierungs- und Löschanweisungen besteht darin, positionierte Anweisungen in durchsuchte zu konvertieren. Dazu ersetzen Sie die WHERE CURRENT OF-Klausel durch eine durchsuchte WHERE-Klausel , die die aktuelle Zeile identifiziert.

Da beispielsweise die CustID-Spalte jede Zeile in der Tabelle "Customers" eindeutig identifiziert, wird die positionierte Delete-Anweisung

DELETE FROM Customers WHERE CURRENT OF CustCursor  

kann in

DELETE FROM Customers WHERE (CustID = ?)  

Der Treiber kann einen der folgenden Zeilenbezeichner in der WHERE-Klausel verwenden:

  • Spalten, deren Werte dienen, um jede Zeile in der Tabelle eindeutig zu identifizieren. Beispielsweise gibt das Aufrufen von SQLSpecialColumns mit SQL_BEST_ROWID die optimale Spalte oder einen Satz von Spalten zurück, die diesem Zweck dienen.

  • Pseudospalten, die von einigen Datenquellen bereitgestellt werden, um jede Zeile eindeutig zu identifizieren. Diese können auch durch Aufrufen von SQLSpecialColumns abgerufen werden.

  • Ein eindeutiger Index, falls verfügbar.

  • Alle Spalten im Resultset.

Genau welche Spalten ein Treiber in der WHERE-Klausel verwenden soll, hängt vom Treiber ab. Bei einigen Datenquellen kann die Ermittlung eines Zeilenbezeichners kostspielig sein. Es ist jedoch schneller auszuführen und garantiert, dass eine simulierte Anweisung aktualisiert oder löscht höchstens eine Zeile. Je nach den Funktionen des zugrunde liegenden DBMS kann die Verwendung eines Zeilenbezeichners für die Einrichtung teuer sein. Es ist jedoch schneller auszuführen und garantiert, dass eine simulierte Anweisung nur eine Zeile aktualisiert oder löscht. Die Option, alle Spalten im Resultset zu verwenden, ist in der Regel viel einfacher einzurichten. Die Ausführung ist jedoch langsamer und kann, wenn die Spalten keine Zeile eindeutig identifizieren, dazu führen, dass Zeilen unbeabsichtigt aktualisiert oder gelöscht werden, insbesondere wenn die Auswahlliste für das Resultset nicht alle Spalten enthält, die in der zugrunde liegenden Tabelle vorhanden sind.

Je nachdem, welche der vorhergehenden Strategien, die der Treiber unterstützt, kann eine Anwendung auswählen, welche Strategie der Treiber mit dem attribut SQL_ATTR_SIMULATE_CURSOR-Anweisung verwenden soll. Obwohl es für eine Anwendung unvorstellbar erscheinen könnte, versehentlich eine Zeile zu aktualisieren oder zu löschen, kann die Anwendung dieses Risiko entfernen, indem sichergestellt wird, dass die Spalten im Resultset jede Zeile im Resultset eindeutig identifizieren. Dies spart dem Fahrer den Aufwand, dies zu tun.

Wenn der Treiber einen Zeilenbezeichner verwendet, wird die SELECT FOR UPDATE-Anweisung abgefangen, die das Resultset erstellt. Wenn die Spalten in der Auswahlliste keine Zeile effektiv identifizieren, fügt der Treiber die erforderlichen Spalten am Ende der Auswahlliste hinzu. Einige Datenquellen verfügen über eine einzelne Spalte, die immer eine Zeile identifiziert, z. B. die ZEILEID-Spalte in Oracle; Wenn eine solche Spalte verfügbar ist, verwendet der Treiber dies. Andernfalls ruft der Treiber SQLSpecialColumns für jede Tabelle in der FROM-Klausel auf, um eine Liste der Spalten abzurufen, die jede Zeile eindeutig identifizieren. Eine häufige Einschränkung, die aus dieser Technik resultiert, besteht darin, dass die Cursorsimulation fehlschlägt, wenn mehrere Tabellen in der FROM-Klausel vorhanden sind.

Unabhängig davon, wie der Treiber Zeilen identifiziert, entfernt er in der Regel die FOR UPDATE OF-Klausel von der SELECT FOR UPDATE-Anweisung , bevor sie an die Datenquelle gesendet wird. Die FOR UPDATE OF-Klausel wird nur mit positionierten Aktualisierungs- und Löschanweisungen verwendet. Datenquellen, die keine positionierten Aktualisierungs- und Löschanweisungen unterstützen, unterstützen sie im Allgemeinen nicht.

Wenn die Anwendung eine positionierte Aktualisierungs- oder Lösch-Anweisung zur Ausführung übermittelt, ersetzt der Treiber die WHERE CURRENT OF-Klausel durch eine WHERE-Klausel , die den Zeilenbezeichner enthält. Die Werte dieser Spalten werden aus einem Cache abgerufen, Standard vom Treiber für jede Spalte, die sie in der WHERE-Klausel verwendet, enthalten ist. Nachdem der Treiber die WHERE-Klausel ersetzt hat, sendet er die Anweisung zur Ausführung an die Datenquelle.

Angenommen, die Anwendung sendet die folgende Anweisung, um ein Resultset zu erstellen:

SELECT Name, Address, Phone FROM Customers FOR UPDATE OF Phone, Address  

Wenn die Anwendung SQL_ATTR_SIMULATE_CURSOR so festgelegt hat, dass eine Eindeutigkeitsgarantie angefordert wird und wenn die Datenquelle keine Pseudospalte bereitstellt, die immer eine Zeile eindeutig identifiziert, ruft der Treiber SQLSpecialColumns für die Tabelle "Customers" auf, ermittelt, dass CustID der Schlüssel zur Tabelle "Customers" ist und dies der Auswahlliste hinzufügt. und entfernt die FOR UPDATE OF-Klausel :

SELECT Name, Address, Phone, CustID FROM Customers  

Wenn die Anwendung keine Garantie der Eindeutigkeit angefordert hat, entfernt der Treiber nur die FOR UPDATE OF-Klausel :

SELECT Name, Address, Phone FROM Customers  

Angenommen, die Anwendung führt einen Bildlauf durch das Resultset durch und sendet die folgende positionierte Aktualisierungsanweisung für die Ausführung, wobei Cust der Name des Cursors über dem Resultset ist:

UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust  

Wenn die Anwendung keine Garantie der Eindeutigkeit angefordert hat, ersetzt der Treiber die WHERE-Klausel und bindet den CustID-Parameter an die Variable im Cache:

UPDATE Customers SET Address = ?, Phone = ? WHERE (CustID = ?)  

Wenn die Anwendung keine Garantie der Eindeutigkeit angefordert hat, ersetzt der Treiber die WHERE-Klausel und bindet die Parameter Name, Address und Telefon in dieser Klausel an die Variablen im Cache:

UPDATE Customers SET Address = ?, Phone = ?  
   WHERE (Name = ?) AND (Address = ?) AND (Phone = ?)