C # et SQL Server: multithreading, connections et transactions

Je cherche une solution à un problème épineux.

Mes collègues et moi avons créé un «moteur» (en C #) qui exécute différentes élaborations sur une database SQL Server.

Initialement, ces élaborations étaient contenues dans de nombreuses procédures stockées appelées en série dans un lot nocturne. C'était un système avec beaucoup de défauts.

Maintenant, nous avons extrait chaque requête de chaque procédure stockée et, peut sembler étrange, nous avons inséré les requêtes dans la database .

(Note: les raisons sont différentes et je ne les répertorie pas toutes, mais vous devez juste savoir que, pour des raisons commerciales, nous n'avons pas la possibilité de faire des versions logicielles fréquentes … mais nous avons beaucoup de liberté avec Scripts SQL).

Principalement, la logique derrière notre moteur est:

  • il y a des phases , appelées séquentiellement
  • chaque phase contient plusieurs étapes , puis subdivisée en Set
  • l'set est un set d'étapes, qui seront exécutées séquentiellement
  • les sets, sauf indication contraire, commencent à fonctionner parallèlement les uns aux autres
  • l'étape qui par défaut n'appartient à aucun set, sera embeddede dans un set (créé lors de l'exécution)
  • Un set avant de commencer peut devoir attendre la fin d'une ou de plusieurs étapes
  • L'étape correspond à des requêtes SQL atomiques (ou presque) ou à des methods C # à exécuter
  • au démarrage, le moteur interroge la database, puis compose les Phases, l'Etape et l'Ensemble (et les configurations associées) … qui seront exécutées

entrez la description de l'image ici

Nous avons créé le moteur, nous avons toutes les configurations … et tout fonctionne.

Cependant, nous avons un besoin: certaines phases doivent avoir une transaction . Si même une seule étape de cette phase échoue, nous devons annuler toute la phase.

Ce qui crée des problèmes, c'est la gestion de la transaction.

Initialement, nous avons créé une seule transaction et une connection pour toute la phase, mais nous nous sums vite rendu count que – à cause du multithreading – ce n'est pas sûr pour les threads.

En outre, après plusieurs tests, nous avons eu des exceptions concernant la transaction. Apparemment, lorsqu'une phase contient BEAUCOUP d'étapes (= nombreuses requêtes de database), la même transaction ne peut pas exécuter d'autres instructions.

Donc, maintenant , nous avons fait un changement et nous sums assurés que chaque étape dans les phases qui nécessitent une transaction ouvre une connection et une transaction par elle-même, et si tout se passe bien, toutes les validations (sinon rollback).

Ça marche. Cependant, nous avons remarqué une limitation: l'utilisation de tables temporaires .

Dans une phase transactionnelle, lorsque je crée une table temporaire temporaire ( #TempTable1 ) dans une étape x, je ne peux pas utiliser #TempTable1 à l'étape suivante y ( SELECT TOP 1 1 FROM #TempTable1 ).

C'est logique: car il s'agit d'une transaction séparée et #TempTable1 est supprimé à la fin de l'instance d'exécution.

Ensuite, nous avons essayé d'utiliser une table temporaire globale ##TempTable2 , mais, à l'étape y, l'exécution du SELECT est bloquée jusqu'à ce que le timeout expire.

J'ai également essayé d'abaisser le niveau d'isolation des transactions, mais rien.

Maintenant, nous sums dans la situation malheureuse de devoir créer de vraies tables au lieu d'utiliser des tables temporaires.

Je cherche un compromis entre l'utilisation des transactions sur un grand nombre d'étapes et l'utilisation de tables temporaires. Je crois que l'accent du discours est la gestion des transactions. Suggestions?