Sperren Sie CREATE TABLE


19

In einer anderen Anwendung stieß ich auf ein schlechtes Design: Mehrere Threads führen EnsureDatabaseSchemaExists()gleichzeitig eine Methode aus, die im Grunde so aussieht:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'MyTable') AND type = N'U') BEGIN

    CREATE TABLE MyTable ( ... );

END

Selbst wenn dieser Code in einer SERIALIZABLE-Transaktion ausgeführt wird, scheint er jedoch nicht threadsicher zu sein (dh der parallele Code versucht, die Tabelle mehrmals zu erstellen). Gibt es eine Möglichkeit, die SELECT-Anweisung zu zwingen, eine Sperre zu erhalten, die verhindert, dass ein anderer Thread dieselbe SELECT-Anweisung ausführt?

Gibt es ein besseres Muster für Multi-Threaded-EnsureSchemaExists () -Methoden?

Antworten:


18

Am besten verwenden Sie eine explizite enthaltende Transaktion und erwerben eine benutzerdefinierte exklusive Sperre, um den gesamten Vorgang ( SELECTund CREATE TABLE) mit sp_getapplock zu schützen . Systemobjekte berücksichtigen Anforderungen der Isolationsstufe nicht und verwenden Sperren nicht wie Benutzertabellen.

Die Racebedingung im Originalcode ist, dass mehrere Threads darauf schließen können, dass die Tabelle nicht existiert, bevor ein Thread die CREATE TABLEAnweisung erreicht.


6
+1 stelle nur sicher, dass die App die SELECT-Prüfung einschließt . Andernfalls führen Sie Deadlocks ein. Idealerweise würde man die App-Sperre im S-Modus bekommen, das Upgrade auf X überprüfen, aber das ist schwierig (gelinde gesagt ...). Am sichersten ist es, X abzurufen und dann die gesamte DB-Schema-Bereitstellung durchzuführen. Es sollte eine seltene Operation sein (z. B. beim Start der App), daher sollte die X-Sperre keine Rolle spielen.
Remus Rusanu

12

Meine Empfehlung wäre es, sich nach besten Kräften anzustrengen. Behandeln Sie den doppelten Fall gegebenenfalls explizit, z. ignoriere es...

Die eigentliche Frage: Warum wird DDL bei Bedarf von mehreren xacts ausgeführt? Normalerweise sind Upgrades und Migrationen eine ernste Angelegenheit, die in bestimmten Zeitfenstern abgewickelt wird. Sie möchten nicht, dass Ihre Migration (Code-First?) Unerwartet einsetzt. Einige dieser Aktualisierungsschritte können bei einem großen Tisch (Größe) Stunden in Anspruch nehmen -Datenoperationen ...)


3
Der Code ist eine Art DatabaseLogger, der seine Tabellen bei Bedarf erstellt. Keine Migration, keine lustige Angelegenheit. Sie haben jedoch vollkommen recht. Ich werde den Code entsprechend umgestalten.
DR

4
Bedenken Sie auch, dass Deployment / Setup für die Ausführung in einem Kontext mit erhöhten Rechten (z. B. von einem Administrator) vollkommen in Ordnung ist, für normale Betriebssysteme jedoch nicht. Derzeit benötigen Sie CREATE TABLEZuschuss für normale
Operationen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.