Frage

Ich habe eine einfache Tabelle mit einem Primärschlüssel. Die meisten der Leseoperationen holen eine Zeile durch den genauen Wert des Schlüssels.

Die Daten in jeder Zeile unterhält eine Beziehung mit Reihen vor und nach ihm in der Reihenfolge des Schlüssels. Also, wenn ich Einsatz eine neue Zeile ich die zwei Zeilen, zwischen denen lesen muß, es betreten wird, eine Berechnung machen und dann einfügen.

Die Sorge, klar ist, dass ein andere Verbindung zugleich eine Zeile mit einem Schlüsselwert in dem gleichen Intervall hinzufügen. Ich decke mich, wenn es genau der gleiche Wert des Schlüssels als der zweiten Einsatz ist, würde scheitern, aber wenn der Schlüsselwert anders ist, aber in dem gleichen Intervall kann die Beziehung gebrochen werden.

scheint die Lösung zu sein, die gesamte Tabelle zum Schreiben zu sperren, wenn ich eine neue Zeile hinzuzufügen entscheiden, oder (wenn möglich, was ich bezweifle) ein Intervall von Schlüsselwerten zu sperren. Aber ich würde es vorziehen, dass die Nur-Lese-Transaktionen würden zu diesem Zeitpunkt nicht blockiert werden.

Ich bin mit ODBC mit libodbc ++ Wrapper für C ++ in dem Client-Programm und Free Edition IBM DB2 (obwohl die DB Wahl noch ändern können). Das ist, was ich dachte zu tun:

  • Starten Sie die Verbindung in der Auto-commit und Standardisolationsmodus
  • , wenn nötig, eine neue Zeile hinzuzufügen, Set auto-commit auf false und Isolationsmodus serialisierten
  • Lesen Sie die Zeilen vor und nach dem neuen Schlüsselwert
  • Rechen- und Einsatz der neuen Zeile
  • commit
  • Rückkehr zurück zu dem Auto-commit und Standardisolationsmodus

Wird dies die Arbeit machen? Werden andere Transaktionen zur gleichen Zeit lesen dürfen? Gibt es andere / bessere Möglichkeiten, es zu tun?

BTW, ich sehe nicht, in dem libodbc ++ i / f eine Möglichkeit, eine Nur-Lese-Transaktion zu spezifizieren. Ist es möglich, in odbc?

EDIT: Danke für die sehr nützliche Antworten, hatte ich Schwierigkeiten Auswahl ein.

War es hilfreich?

Lösung

Wenn Ihre Datenbank in SERIALIZABLE-Modus ist, werden Sie keine Probleme haben, überhaupt nicht. Bei einem Schlüssel K, um die vorherigen und nächsten Schlüssel erhalten Sie die folgenden Abfragen ausführen müssen:

select key from keys where key > K order by key limit 1;      # M?
select key from keys where key < K order by key desc limit 1; # I?

Die oben genannten Arbeiten in MySQL. Diese äquivalente Abfrage funktioniert in DB2 (aus den Kommentaren):

select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);

Die erste Abfrage richtet eine Bereichssperre, verhindert, dass andere Transaktionen von einem Schlüssel K größer als das Einfügen und kleiner als oder gleich M.

Die zweite Abfrage richtet eine Bereichssperre, verhindert, dass andere Transaktionen von Einfügen eines Schlüssels weniger als K und größer als oder gleich I.

Der eindeutige Index auf dem Primärschlüssel K verhindert zweimal eingesetzt wird. So können Sie vollständig abgedeckt sind.

Dies ist, was Transaktionen über; so dass Sie Ihren Code, als ob die gesamte Datenbank gesperrt schreiben können.

Hinweis: Dies erfordert eine Datenbank, die wahre Serialisierung unterstützt. Glücklicherweise funktioniert DB2. Andere DBMS, dass die Unterstützung wahr Serialisierbarkeit: SQLServer und MySQL / InnoDB. DBMS, die nicht: Oracle, PostgreSQL

Andere Tipps

Wenn Sie Ihre Datenbank und Speicher-Engine, dass erlauben, sollten Sie SELECT FOR UPDATE für beide Reihen ausgeben Sie versuchen, zwischen einzufügen.

Dies wird Konflikt mit jedem gleichzeitigen SELECT FOR UPDATE.

Der Nachteil ist, dass eine Sperre der Zeilen 10 und 12 (zum Einsatz 11) wird auch verhindern, dass die Auswahl und 8 10 (zum Einsatz 9).

InnoDB in MySQL platzieren kann auch eine next-key Sperre auf dem Index, das Schloss des Indexdatensatzes und die Lücke zwischen dem nächsten Datensatz ist.

In diesem Fall würden Sie nur eine SELECT FOR UPDATE in der ersten Zeile ausgeben müssen und damit gleichzeitig eine Zeile einfügen davor.

Dies erfordert jedoch zwingt den Index und die Bereitstellung eines range Zustand auf dem Index, die je nach Ihrer Anfrage kann oder nicht möglich sein.

Ihr allgemeiner Ansatz ist richtig. Aber Sie sollten eine SELECT-Anweisung, die die beiden Zeilen und alle möglichen Reihen dazwischen abdeckt. Zum Beispiel:

SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10

In Datenbanksystemen mit pessimistischen Sperren und Transaktionsisolationsstufe serializable, diese SELECT-Anweisung sollte neue Zeilen verhindern eingefügt werden, dass würde das Ergebnis der SELECT ändern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top