2009-10-14 16 views
8

Tengo una confusión básica acerca de cómo las transacciones y msdtc trabajan juntas.confusión sobre transacciones y msdtc

Tengo una aplicación básica de winforms de servidor/cliente. La aplicación usa transactionscope para encapsular varios comandos sql que se ejecutan en el servidor sql.

La aplicación parecía funcionar bien cuando habilitaba el acceso a la red msdtc solo en el servidor. Entonces, un día, dejó de funcionar para indicar que el acceso a la red no estaba habilitado.

Ahora parece que tengo que habilitar el acceso a la red msdtc tanto en la computadora cliente como en el servidor para que workscope funcione.

¿Funciona el servicio msdtc del cliente o del servidor? O tal vez son las dos?

¿Alguien tiene una guía sobre si el acceso a la red msdtc es necesario tanto en el cliente como en el servidor o solo en el servidor?

Respuesta

10

Si está utilizando MSDTC, necesitará el cliente (su aplicación) y el servidor (base de datos) para ejecutar MSDTC y también para configurarlo correctamente.

Esto puede ser motivo de dolor, especialmente cuando se trata de firewalls. Si tiene problemas, vea Troubleshooting Problems with MSDTC. Habla de BizTalk pero se aplica a MSDTC en general. DTCPING es también tu amigo.

Ahora, si utiliza SQL Server 2005 y una versión superior, solo tiene acceso a una base de datos, usa una conexión de base de datos y no está transfiriendo transacciones entre dominios de aplicación, entonces no debería requerir el uso de MSDTC. En esas circunstancias, el administrador de transacciones de System.Transactions administrará sus transacciones por usted. Si se produce alguna de las situaciones anteriores, la transacción se promocionará a una transacción distribuida (y el administrador de transacciones será MSDTC). Consulte Transaction Management Escalation para obtener más información.

En general, es mejor evitar el uso de MSDTC si no lo necesita. es decir, si solo está tratando con una única base de datos SQL Server 2005+, intente diseñar su código para no utilizar MSDTC. Además de los problemas de configuración, DTC impone una penalización de rendimiento porque todas las llamadas a MSDTC están fuera de proceso combinadas con la sobrecarga del protocolo de confirmación de dos fases (que usa MSDTC).

En términos de lo que está sucediendo en su situación específica, es difícil de decir. Si su código no ha cambiado, ¿tal vez las reglas del firewall han cambiado? También he visto que las Actualizaciones de Windows cambian la configuración de DTC (por seguridad), lo que causó un problema.

actualización basada en comentario:

Para la promoción de monitorización de transacciones o la escalada, si usted no está utilizando ningún transacciones distribuidas creo que se podría utilizar algunos de los contadores de rendimiento Coordinador de transacciones distribuidas para rastrear las transacciones confirmadas. Si prueba, puede desactivar MSDTC y ver si su código falla. Otra forma sería supervisar las transacciones en SQL Server. Desde la perspectiva de la codificación, podría tratar de manejar el evento DistributedTransactionStarted y hacer algo de registro (pero elimine ese código antes de pasar a producción).

Para obtener un ejemplo de código con una sola conexión, vaya a la página TransactionScope en MSDN. Básicamente, cree un TransactionScope, cree un SqlConnection, trabaje con SqlConnection, cierre la conexión, llame a scope.Complete().

Tenga en cuenta que si está utilizando métodos de Adaptador de datos, ellos administran automáticamente su conexión por lo que la conexión se cierra o se devuelve al grupo de conexiones. De cualquier manera, si se llama a otra operación, la transacción se promocionará a una transacción DTC. Vea System.Transactions and connection pooling para más detalles.

+0

Gracias por la gran información. Me encantaría no usar MSDTC. Estoy usando sql2005, 1 db, no estoy pasando dominios de aplicaciones, pero no estoy seguro si estoy usando 1 conexión. ¿Sería posible dar un pequeño ejemplo de una transacción con múltiples sentencias sql que no se elevarían a dtc? ¿Hay alguna herramienta o alguna otra forma de decir si mis transacciones se están elevando a msdtc? – muhan

7

Para ampliar @ explicación de Tuzo, aquí es un ejemplo de un comando que siempre escalará:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    scope.Complete(); 
} 

En la práctica, la conexión y el comando debe ser en otra clase, etc., pero se obtiene la idea. Incluso si la cadena de conexión está en la misma base de datos, escalará usando DTC, porque son dos conexiones. A-escalada no sería transacción:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    //...some other command, etc. 
    } 
    scope.Complete(); 
} 

Esto es mejor código de todos modos, porque se abre la conexión, haga lo que necesita, y cerrar tan pronto como sea posible. Esto significa que debes pensar en la administración de tu conexión. Dependiendo de su aplicación, puede implementar esto de manera diferente. Por ejemplo:

using(var scope = new TransactionScope()) 
using(var conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 
    var myService = new MyService(conn); 
    var myService2 = new MyService2(conn); 
    myService.DoSomething(); 
    myService2.DoSomething(); 
    scope.Complete(); 
} 

Existen varias formas de implementar esto. El bloque de aplicaciones de acceso a datos de Enterprise Library y varios ORM también pueden ayudarlo a manejar sus conexiones y transacciones de manera más eficiente.

+1

Enterprise Library Data Access Block puede ayudar porque mantiene una lista interna de transacciones activas y sus conexiones (en la clase TransactionScopeConnections). La misma conexión se utiliza durante el tiempo de vida de la transacción, por lo que la transacción no escalará a una transacción distribuida. También tiene el beneficio de hacer sus interfaces más limpias ya que no necesita pasar la conexión a cada método que necesita usar una conexión de base de datos. –

+1

PARA usuarios de SQLserver 2008: El primer ejemplo de su código no se escalará en SQLserver 2008. Escalará solo si no cierra la primera conexión antes de abrir la segunda (por ejemplo, si anida el tercer uso de statament dentro del segundo usando declaración). – mipe34

0

Actualización: Encontré un artículo que explica por qué las transacciones se promocionan desde LTM a MSDTC cuando solo se usan tanto GetData como Update en el mismo adaptador de datos dentro de un TransactionScope junto con una solución alternativa.

El TableAdapters + Transacciones definitiva entrada en el blog http://blah.winsmarts.com/2006/06/18/the-definitive-tableadapters--transactions-blog-post.aspx

entiendo la parte de tener múltiples conexiones abiertas a la vez la escalada de una transacción para ser distribuido. Sin embargo, tengo un problema donde solo hay una conexión y una consulta en contra de una base de datos que está escalando. No hay ninguna transacción en el procedimiento almacenado tampoco. Si alguien tiene una pista, me gustaría saber de ella. Desde mi ejemplo de código, el "adaptador. Actualización (tabla)" activará una transacción distribuida.

He sacado las entrañas del código de mi proyecto existente y simplifiqué casi todo lo que estaba pasando, y sigo teniendo los mismos problemas. Básicamente, esto crea un conjunto de datos con un adaptador de tabla y lo configura con un procedimiento almacenado para seleccionar, insertar y eliminar. Selecciono todos los registros relacionados con un usuario específico. Luego, dependiendo de si existe un "myPPID" para uno de los registros, lo agrego o elimino. Luego llamo al método de actualización y veo que la escalada de la transacción se distribuirá mirando las estadísticas de transacciones en los servicios de los componentes.

Estoy usando Windows XP Pro SP3 y .Net Framework 3.5 para el programa cliente. Se conecta a una base de datos SQL 2005 a través de LAN a Windows Server 2003 R2 Enterprise Edition SP2.

private void button1_Click(object sender, EventArgs e) 
{ 
int userId = 3; 
int myPPId = 881; 
using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DataSet1TableAdapters.AssignedPPTableAdapter adapter 
    = new MSDTCPromotionTest.DataSet1TableAdapters.AssignedPPTableAdapter()) 
    { 
     using (DataSet1.AssignedPPDataTable table = adapter.GetData(userId)) 
     { 
      DataSet1.AssignedPPRow row = table.FindByUserIdmyPPId(
       userId, myPPId); 
      if (row == null) 
      { 
       table.AddAssignedPPRow(userId, myPPId, string.Empty, 
        string.Empty, true); 
      } 
      else 
      { 
       row.Delete(); 
      } 
      adapter.Update(table); 
     } 
     ts.Complete(); 
    } 
} 
} 

La cadena de conexión es nada especial:

<add name="ConnectionString" connectionString=" 
Data Source=devdb; 
Initial Catalog=&quot;TEST MSDTC&quot;; 
Integrated Security=True" 
providerName="System.Data.SqlClient" /> 

Además, los procedimientos almacenados son llamadas crud simples.

Crear:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Insert] 
(
    @UserId INT, 
    @myPPId int 
) 
AS 
SET NOCOUNT ON; 
INSERT INTO [UsermyPP] ([UserID],[myPPID],[DateCreated]) 
    VALUES (@UserId,@myPPId,GETutcDATE()) 

Leer:

ALTER procedure [dbo].[p_UserForm_AssignedPP_SelectByUserId] 
(
    @UserId int 
) 
AS 
SELECT 
    [UserId], 
    [myPPId], 
    '' Title, 
    '' Abbreviation, 
    0 IsArchived 
from 
    UsermyPP unpp 
where 
    unpp.[userid] = @UserId 

Eliminar:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete] 
(
    @Original_UserId INT, 
    @Original_MyPPId INT 
) 
AS 
SET NOCOUNT ON; 
DELETE FROM usermypp WHERE [UserID] = @Original_UserId 
    AND [MyPPID] = @Original_MyPPId 
Cuestiones relacionadas