Le champ des transactions passe automatiquement au MSDTC sur certaines machines?

dans notre projet, nous utilisons Transactionsscope pour nous assurer que notre couche d'accès aux données effectue ses actions dans une transaction. Nous visons à et non exiger que le service MSDTC soit activé sur les machines de notre utilisateur final.

problème est, sur la moitié de nos machines de développeurs, nous pouvons exécuter avec MSDTC désactivé. L'autre moitié doit l'avoir activé ou ils reçoivent le message D'erreur "MSDTC on [SERVER] is unavailable" .

cela m'a vraiment fait me gratter la tête et m'a fait sérieusement envisager de revenir à une solution de type opaque maison basée sur ADO.NET objets de transaction. C'est en apparence insensé - le même code qui fonctionne (et ne dégénère pas) sur la moitié de de notre développeur fait escalader sur l'autre développeur.

j'espérais une meilleure réponse à Trace pourquoi une transaction est transmise au CIPH mais malheureusement, non.

voici un échantillon de code qui causera le problème, sur les machines qui tentent de s'intensifier, il tente de s'intensifier sur la deuxième connexion.Open() (et oui, il n'y a pas d'autre connexion ouverte à l'époque.)

using (TransactionScope transactionScope = new TransactionScope() {
   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();
         using (SqlDataReader reader = command.ExecuteReader()) {
            // use the reader
            connection.Close();
         }
      }
   }

   // Do other stuff here that may or may not involve enlisting 
   // in the ambient transaction

   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();  // Throws "MSDTC on [SERVER] is unavailable" on some...

         // gets here on only half of the developer machines.
      }
      connection.Close();
   }

   transactionScope.Complete();
}

Nous avons vraiment cherché et essayé de comprendre cela. Voici quelques informations sur les machines sur lesquelles il fonctionne:

  • Dev 1: Windows 7 x64 SQL2008
  • Dev 2: Windows 7 x86 SQL2008
  • Dev 3: Windows 7 x64 SQL2005 SQL2008 1519260920"

développeurs, il ne fonctionne pas sur:

  • Dev 4: Windows 7 x64, SQL2008 SQL2005
  • Dev 5: Windows Vista x86, SQL2005
  • Dev 6: Windows XP X86, SQL2005
  • mon PC Maison: Windows Vista Home Premium, x86, SQL2005

je dois ajouter que toutes les machines, dans un effort pour traquer le problème, ont été entièrement corrigé avec tout ce qui est disponible à partir de Microsoft Update.

Maj 1:

cette page indique que les conditions suivantes feront en sorte qu'une transaction sera transmise au CIPH:

  1. au moins une ressource durable qui ne supporte pas les notifications monophasées est enrôlée dans la transaction.
  2. au moins deux ressources durables qui prennent en charge les notifications monophasées sont engagées dans la transaction. Par exemple, l'enrôlement d'une connexion unique à ne pas causer un transaction à promouvoir. Cependant, chaque fois que vous ouvrez une deuxième connexion à une base de données provoquant l'enrôlement de la base de données, le système.L'infrastructure des Transactions détecte qu'il s'agit de la deuxième ressource durable de la transaction et l'achemine vers une transaction de type MSDTC.
  3. Une demande de "maréchal" la transaction à un domaine d'application différent ou différents processus est invoqué. Par exemple, la sérialisation de l'objet de transaction à travers une limite de domaine d'application. L'objet de transaction est marshaled-by-value, ce qui signifie que toute tentative de le passer à travers une limite de domaine d'application (même dans le même processus) entraîne la sérialisation de l'objet de transaction. Vous pouvez passer les objets de transaction en faisant un appel sur une méthode distante qui prend une Transaction comme paramètre ou vous pouvez essayer d'accéder à un composant à distance avec services transactionnels. Cette sérialisation de l'objet de transaction se traduit par une indexation, comme lorsqu'une transaction est sérialisée à travers un domaine d'application. Il est distribué et le local gestionnaire de transactions n'est plus adéquat.

nous ne faisons pas l'expérience #3. #2 ne se produit pas parce qu'il n'y a qu'une connexion à la fois, et c'est aussi à une seule "ressource durable". Y a-t-il un moyen que le #1 puisse se produire? Une configuration SQL2005 / 8 qui ne supporte pas les notifications monophasées?

Maj 2:

Ré-examiné, personnellement, tout le monde versions SQL Server - "Dev 3" a effectivement SQL2008, et" Dev 4 " est en fait SQL2005. Ça m'apprendra à ne plus jamais faire confiance à mes collègues. ;) À cause de ce changement dans les données, je suis presque sûr que nous avons trouvé notre problème. Nos développeurs SQL2008 ne rencontraient pas le problème parce que SQL2008 a des quantités abondantes de super inclus que SQL2005 n'a pas.

Il me dit aussi que parce que nous allons soutenir SQL2005 que nous nous ne pouvons pas utiliser Transactionsscope comme nous l'avons fait, et si nous voulons utiliser Transactionsscope nous allons avoir besoin de passer un seul objet SqlConnection autour...ce qui semble problématique dans les situations où la connexion SQL ne peut pas être facilement transmise...ça sent juste l'instance global-SqlConnection. Pew!

Update 3

juste pour clarifier ici dans la question:

SQL2008:

  • permet connexions multiples à l'intérieur d'un même champ de transactions (comme le montre le code échantillon ci-dessus).)
  • mise en garde #1: si ces connections SQL multiples sont imbriquées, c'est-à-dire que deux ou plusieurs connections SQL sont ouvertes en même temps, Transactionsscope va immédiatement monter à DTC.
  • mise en garde #2: si une connexion SQL supplémentaire est ouverte à une autre 'ressource durable' (c.-à-d. un serveur SQL différent,) elle va immédiatement s'intensifier a DTC 1519260920"

SQL2005:

  • ne permet pas de raccordements multiples au cours d'une même période. Il s'intensifiera quand / si une seconde connexion SQL est ouverte.

Jour 4

dans l'intérêt de rendre cette question encore plus d'un mess utile, et juste pour plus de clarté, voici comment vous pouvez obtenir SQL2005 pour escalader à DTC avec un simple SqlConnection :

using (TransactionScope transactionScope = new TransactionScope()) {
   using (SqlConnection connection = new SqlConnection(connectionString)) {
      connection.Open();
      connection.Close();
      connection.Open(); // escalates to DTC
   }
}

cela me semble juste cassé, mais je suppose que je peux comprendre si chaque appel à SqlConnection.Open() est accaparant de la piscine de connexion.

" pourquoi cela pourrait-il arriver?" bien, si vous utilisez un SqlTableAdapter contre cette connexion avant qu'elle ne soit ouverte, le SqlTableAdapter ouvrira et fermera la connexion, finissant effectivement la transaction pour vous parce que tu ne peux pas la rouvrir.

donc, fondamentalement, pour utiliser avec succès TransactionScope avec SQL2005 vous devez avoir une sorte d'objet de connexion globale qui reste ouvert du point de la première TransactionScope est instancié jusqu'à ce qu'il ne soit plus nécessaire. Outre le code-odeur d'un objet global de connexion, ouvrir la connexion en premier et la fermer en dernier est en désaccord avec la logique d'ouvrir une connexion aussi tard que possible et de la fermer dès que possible possible.

272
demandé sur Community 2009-11-07 01:24:33

6 réponses

SQL Server 2008 peut utiliser plusieurs SQLConnection en un TransactionScope sans escalade, à condition que les connexions ne soient pas ouvertes en même temps, ce qui entraînerait de multiples connexions TCP "physiques" et donc nécessiter une escalade.

je vois que certains de vos développeurs ont SQL Server 2005 et d'autres ont SQL Server 2008. Êtes-vous sûr d'avoir correctement identifié ceux qui s'intensifient et ceux qui ne le sont pas?

L'explication la plus évidente serait que les développeurs avec SQL Server 2008 sont ceux qui ne sont pas en escalade.

70
répondu Joe 2018-08-25 05:06:47

Le résultat de mes recherches sur le sujet:

enter image description here

Voir Éviter l'Escalade pour les Transactions Distribuées

j'enquête toujours sur le comportement d'escalade D'Oracle: Faire des transactions couvrant de multiples connexions à la même DB remonter à la DTC?

53
répondu Peter Meinl 2011-03-23 07:15:56

ce code causera une escalade lors de la connexion à 2005.

vérifier la documentation sur MSDN - http://msdn.microsoft.com/en-us/library/ms172070.aspx

Promotable Transactions in SQL Server 2008

dans la version 2.0 du .net Framework et SQL Server 2005, ouvrant une seconde la connexion à l'intérieur TransactionScope promouvoir automatiquement la transaction distribuée complète transaction, même si les deux connexions ont utilisé une connexion identique chaîne. Dans ce cas, un distribué opération ajoute une surcharge inutile qui diminue les performances.

à partir de SQL Server 2008 et version 3.5 du cadre .NET, les transactions locales ne sont plus promu transactions distribuées si une autre connexion est ouverte dans le transaction après la précédente la transaction est fermé. Cela nécessite aucune modification de votre code si vous utilisant déjà la mise en commun des connexions et s'enrôler dans des transactions.

Je ne peux pas expliquer pourquoi Dev 3: Windows 7 x64, SQL2005 succède et Dev 4: Windows 7 x64 échoue. Êtes-vous sûr que c'est pas l'inverse?

31
répondu hwiechers 2009-11-07 17:33:54

Je ne sais pas pourquoi cette réponse a été supprimée, mais elle semble contenir des renseignements pertinents.

, a répondu le 4 Août '10 à 17:42 Eduardo

  1. Set Enrôler=false sur la chaîne de connexion pour éviter automatique de l'enrôlement de la transaction.

  2. inscrire manuellement la connexion en tant que participants dans le champ d'application de la transaction. [ article original périmé] ou faites ceci: comment empêcher la promotion automatique MSDTC [archive.is]

8
répondu Chris Marisic 2017-05-23 12:03:09

Je ne suis pas sûr que la connexion imbriquée soit le problème. J'appelle une instance locale de SQL server et elle ne génère pas le DTC??

    public void DoWork2()
    {
        using (TransactionScope ts2 = new TransactionScope())
        {
            using (SqlConnection conn1 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;"))
            {
                SqlCommand cmd = new SqlCommand("Insert into Log values(newid(),'" + "Dowork2()" + "','Info',getDate())");
                cmd.Connection = conn1;
                cmd.Connection.Open();
                cmd.ExecuteNonQuery();

                using (SqlConnection conn2 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;Connection Timeout=100"))
                {
                    cmd = new SqlCommand("Insert into Log values(newid(),'" + "Dowork2()" + "','Info',getDate())");
                    cmd.Connection = conn2;
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();
                }
            }

            ts2.Complete();
        }
    }
2
répondu Iftikhar Ali 2013-02-20 13:14:51

TransactionScope toujours l'escalade à la transaction DTC, si vous utilisez l'accès plus d'une connexion à l'intérieur. La seule façon dont le code ci-dessus peut fonctionner avec DTC désactivé est si par une énorme chance vous obtenez la même connexion à partir de la piscine de connexion deux fois.

" le problème est, sur la moitié de nos machines de développeurs, nous pouvons exécuter avec MSDTC désactivé." Êtes-vous sûr sûr il est désactivé ;)

1
répondu amateur 2009-11-07 00:28:12