Comment une transaction T-SQL n'est-elle pas sécurisée pour les threads?

Le code (aseptisé) suivant produit parfois ces erreurs:

Impossible de supprimer la table 'database.dbo.Table', car elle n'existe pas ou vous n'avez pas la permission.
Il y a déjà un object nommé 'Table' dans la database.

begin transaction if exists (select 1 from database.Sys.Tables where name ='Table') begin drop table database.dbo.Table end Select top 3000 * into database.dbo.Table from OtherTable commit select * from database.dbo.Table 

Le code peut être exécuté plusieurs fois simultanément. Quelqu'un sait pourquoi ça casse?

Dans quelle partie du code empêchez-vous les access multiples à cette ressource?

 begin transaction if exists (select 1 from database.Sys.Tables where name ='Table') begin drop table database.dbo.Table end Select top 3000 * into database.dbo.Table from OtherTable commit 

Commencer la transaction ne le fait pas. Il ne configure que pour un scénario de validation / restauration sur les lignes ajoutées aux tables.

Le (si existe, drop) est une condition de course, avec la recréation de la table avec (select..into). Mutiliple personnes tomber dans ce code tout à la fois certainement causer toutes sortes d'erreurs. Certains créent des tables que d'autres viennent de détruire, d'autres abandonnent des tables qui n'existent plus, d'autres abandonnent des tables que certains sont en train d'insert. POUAH!

Tenez count des suggestions de la table temporaire des autres ou utilisez un verrou d'application pour empêcher les autres users d'entrer ce code si la ressource critique est occupée. Les transactions sur drop / create ne sont pas ce que vous voulez.

Puis-je requestr pourquoi vous faites cela en premier? Vous devriez vraiment envisager d'utiliser des tables temporaires ou proposer une autre solution.

Je ne suis pas sûr que les déclarations DDL se comportent de la même manière dans les transactions que les instructions DML et ont vu un billet de blog avec un comportement étrange et la création de procédures stockées dans un DDL.

À partir de cela, vous pouvez vérifier le niveau d'isolation de votre transaction et le définir sur Serialized.

modifier

Basé sur un test rapide, j'ai couru le même sql dans deux connections différentes, et quand j'ai créé la table mais n'ai pas commis la transaction, la deuxième transaction bloquée. Donc, il semble que cela devrait fonctionner. Je voudrais encore mettre en garde contre ce type de design.

Si vous utilisez cette table pendant ce process, je suggère d'utiliser une table temporaire ou, selon la quantité de données, une table RAM. J'utilise fréquemment des tables de ram pour éviter les coûts de transaction et économiser sur l'activité du disque.