TransactionScope escalando automáticamente a MSDTC en algunas máquinas?


En nuestro proyecto estamos usando TransactionScope para garantizar que nuestra capa de acceso a datos realice sus acciones en una transacción. Nuestro objetivo es no requerir que el servicio MSDTC esté habilitado en las máquinas de nuestros usuarios finales.

El problema es que, en la mitad de nuestras máquinas de desarrolladores, podemos ejecutar con MSDTC deshabilitado. La otra mitad debe tenerlo habilitado o reciben el mensaje de error "MSDTC on [SERVER] is unavailable".

Realmente me tiene rascándome la cabeza y me tiene considerar seriamente la posibilidad de volver a una solución similar a TransactionScope basada en ADO.NET objetos de transacción. Es aparentemente una locura-el mismo código que funciona (y no se intensifica) en la mitad de nuestro desarrollador hace escalar en el otro desarrollador.

Esperaba una mejor respuesta para Rastrear por qué una transacción se escalona a DTC pero desafortunadamente no lo hace.

Aquí hay una muestra de código que causará el problema, en las máquinas que intentan para escalar, intenta escalar en la segunda conexión.Open () (y sí, no hay ninguna otra conexión abierta en ese momento.)

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();
}

Realmente hemos cavado y tratado de resolver esto. Aquí hay información sobre las máquinas en las que funciona:

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

Desarrolladores en los que no funciona:

  • Dev 4: Windows 7 x64, SQL2008 SQL2005
  • Dev 5: Windows Vista x86, SQL2005
  • Dev 6: Windows XP X86, SQL2005
  • Mi PC de casa: Windows Vista Home Premium, x86, SQL2005

Debo añadir que todas las máquinas, en un esfuerzo por encontrar el problema, han sido completamente parcheado con todo lo que está disponible en Microsoft Update.

Actualización 1:

Esa página de escalado de transacciones de MSDN indica que las siguientes condiciones harán que una transacción se incremente a DTC:

  1. En la transacción se incluye al menos un recurso duradero que no admite notificaciones monofásicas.
  2. En la transacción se incluyen al menos dos recursos duraderos que admiten notificaciones monofásicas. Por ejemplo, enlistar una sola conexión con no causa que una transacción sea promovida. Obstante, cada vez que se abre una segunda conexión a una base de datos haciendo que la base de datos para enlistar, el Sistema.Transactions infrastructure detecta que es el segundo recurso duradero de la transacción y lo convierte en una transacción MSDTC.
  3. Se invoca una solicitud para "ordenar" la transacción a un dominio de aplicación diferente o proceso diferente. Por ejemplo, la serialización del objeto transaction a través de un límite de dominio de aplicación. El objeto de transacción se clasifica por valor, lo que significa que cualquier intento de pasarlo a través de un límite de dominio de aplicación (incluso en el mismo proceso) resulta en la serialización del objeto de transacción. Puede pasar los objetos de transacción haciendo una llamada a un método remoto que toma una Transacción como parámetro o puede intentar acceder a un componente de servicio transaccional remoto. Esto serializa el objeto de transacción y resulta en una escalada, como cuando una transacción se serializa en un dominio de aplicación. Se está distribuyendo y el administrador de transacciones local ya no es adecuado.

No estamos experimentando el #3. #2 no está sucediendo porque solo hay una conexión a la vez, y también a un solo 'recurso duradero'. ¿Hay alguna manera de que el #1 pueda estar sucediendo? ¿Alguna configuración de SQL2005 / 8 que hace que no admita notificaciones monofásicas?

Actualización 2:

Re-investigado, personalmente, todas las versiones de SQL Server - "Dev 3" en realidad tiene SQL2008, y "Dev 4" es en realidad SQL2005. Eso me enseñará a no volver a confiar en mis compañeros de trabajo. ;) Debido a este cambio en los datos, estoy bastante seguro de que hemos encontrado nuestro problema. Nuestros desarrolladores de SQL2008 no estaban experimentando el problema porque SQL2008 tiene copiosas cantidades de awesome incluidas que SQL2005 no tiene.

También me dice que porque vamos a apoyar SQL2005 que no podemos usar TransactionScope como lo hemos sido, y si queremos usar TransactionScope vamos a necesitar pasar un único objeto SqlConnection alrededor...lo que parece problemático en situaciones donde la conexión SqlConnection no se puede pasar fácilmente around...it solo huele a instancia global-SqlConnection. ¡Pew!

Actualización 3

Solo para aclarar aquí en la pregunta:

SQL2008:

  • Permite múltiples conexiones dentro de un único TransactionScope (como se demuestra en el código de ejemplo anterior.)
  • Advertencia # 1: Si esas múltiples conexiones SqlConnections están anidadas, es decir, dos o más SqlConnections se abren al mismo tiempo, TransactionScope escalará inmediatamente a DTC.
  • Advertencia #2: Si se abre una conexión SqlConnection adicional a un 'recurso duradero' diferente (es decir, un servidor SQL diferente), se escalará inmediatamente a DTC

SQL2005:

  • No permite múltiples conexiones dentro de un único TransactionScope, punto. Se escalará cuando / si se abre una segunda conexión SqlConnection.

Actualización 4

En el interés de hacer que esta pregunta sea aún más de un lío útil, y solo para mayor claridad, aquí está cómo puede lograr que SQL2005 aumente a DTC con un single SqlConnection:

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

Esto me parece roto, pero supongo que puedo entender si cada llamada a SqlConnection.Open() se está grabando desde el grupo de conexiones.

"¿Por qué podría pasar esto?" Bueno, si usas un SqlTableAdapter contra esa conexión antes de que se abra, el SqlTableAdapter se abrirá y cierre la conexión, finalizando efectivamente la transacción por usted porque ahora no puede volver a abrirla.

Así que, básicamente, para usar con éxito TransactionScope con SQL2005, necesita tener algún tipo de objeto de conexión global que permanezca abierto desde el punto en que se instancie la primera TransactionScope hasta que ya no sea necesario. Además del olor a código de un objeto de conexión global, abrir la conexión primero y cerrarla al final está en desacuerdo con la lógica de apertura una conexión lo más tarde posible y cerrarla lo antes posible.

Author: Community, 2009-11-07

6 answers

SQL Server 2008 puede usar múltiples SQLConnections en uno TransactionScope sin escalar, siempre que las conexiones no estén abiertas al mismo tiempo, lo que resultaría en múltiples conexiones TCP "físicas" y, por lo tanto, requeriría escalar.

Veo que algunos de sus desarrolladores tienen SQL Server 2005 y otros tienen SQL Server 2008. ¿Está seguro de haber identificado correctamente cuáles están escalando y cuáles no?

La explicación más obvia sería que los desarrolladores con SQL Server 2008 son los unos que no están escalando.

 70
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-25 05:06:47

El resultado de mi investigación sobre el tema:

introduzca la descripción de la imagen aquí

Véase Evite la escalada no deseada a Transacciones Distribuidas

Todavía estoy investigando el comportamiento de escalada de Oracle: ¿Las transacciones que abarcan múltiples conexiones a la misma base de datos escalan a DTC?

 53
Author: Peter Meinl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-23 07:15:56

Ese código causará una escalada al conectarse a 2005.

Compruebe la documentación en MSDN - http://msdn.microsoft.com/en-us/library/ms172070.aspx

Transacciones promovibles en SQL Server 2008

En la versión 2.0 de. NET Framework y SQL Server 2005, abriendo un segundo conexión dentro de un TransactionScope automáticamente promover la transaction to a full distributed transaction, even if both relación estaban usando conexión idéntica cadena. En este caso, un distribuido la transacción agrega gastos generales innecesarios eso disminuye el rendimiento.

Comenzando con SQL Server 2008 y versión 3.5 de. NET Framework, las transacciones locales ya no son promovido a transacciones distribuidas si se abre otra conexión en el transacción después de la anterior la transacción está cerrada. Esto requiere no hay cambios en su código si usted es ya está usando la conexión pooling and alistarse en transacciones.

No puedo explicar por qué Dev 3: Windows 7 x64, SQL2005 tiene éxito y Dev 4: Windows 7 x64 falla. ¿Estás seguro de que no es al revés?

 31
Author: hwiechers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-07 17:33:54

No se porque esta respuesta fue borrada pero parece tener alguna información relevante.

Respondió ago 4 '10 a las 17: 42 Eduardo

  1. Establezca Enlist=false en la cadena de conexión para evitar el alistamiento automático en la transacción.

  2. Enlistar manualmente la conexión como participantes en el ámbito de la transacción. [artículo original obsoleto] o haga esto: Cómo evitar la promoción automática de MSDTC [archive.is]

 8
Author: Chris Marisic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:09

No estoy muy seguro de si la conexión anidada es el problema. Estoy llamando a una instancia local de SQL server y no genera el 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
Author: Iftikhar Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-20 13:14:51

TransactionScope siempre aumenta a transacción DTC, si usa acceso a más de 1 conexión dentro. La única forma en que el código anterior puede funcionar con DTC deshabilitado es si por una gran probabilidad obtiene la misma conexión del grupo de conexiones ambas veces.

"El problema es que, en la mitad de nuestras máquinas de desarrolladores, podemos ejecutar con MSDTC deshabilitado." Está seguro de que está desactivado;)

 1
Author: amateur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-07 00:28:12