2009-10-09 8 views
6

È possibile utilizzare il modello di programmazione System.Transactions senza supporto per le transazioni distribuite?.NET: come disabilitare la promozione in System.Transactions?

qualcosa come

TransactionConfig.DisablePromotion = true; 
+0

Che problema hai che ti fa venire voglia di disabilitare la promozione? –

+0

Uso un server collegato per connettere due server Sql. Per la logica del server collegato ho usato transazioni esplicite, quindi l'integrità va bene. Ma quando ho finito con il server collegato, SQL Server non rilascia la connessione interna. Quando la mia applicazione si avvia e utilizza transazioni implicite (per semplicità), esse funzionano sempre contro UN database. Ma la promozione si verifica perché la connessione al server collegato è ancora aperta. – andreas

risposta

10

No, non è possibile disabilitare la promozione della transazione tramite una proprietà o una configurazione. L'unico modo per disabilitare la promozione delle transazioni è evitare le condizioni che fanno sì che la transazione venga promossa a una transazione distribuita.

Per evitare transaction management escalation è necessario:

  • dispone di SQL Server 2005 o superiore, come database

  • se SQL Server 2005, utilizzare solo una connessione al database per la durata della transazione . (SQL Server 2008 permetterà di utilizzare più connessioni all'interno di una transazione senza la promozione che si verificano.)

  • accedere solo database

  • non passa la transazione attraverso domini applicativi


Il motivo delle regole è garantire lo ACID properties della transazione.

Per fare un esempio, supponiamo per un minuto che si potrebbe specificare di non promuovere una transazione (come nel tuo frammento di codice), ma il codice di accessi due basi di dati (lo so - il codice utilizza un solo database). Quindi ora hai specificato di non utilizzare le transazioni distribuite, hai avviato una transazione e hai specificato che due database dovrebbero essere entrambi all'interno di quella unità di lavoro. Esiste un conflitto tra le proprietà ACID della transazione e il desiderio di evitare una transazione distribuita. Mi sembra che ci sarebbero due modi per gestire questo: o promuovere la transazione su una transazione distribuita (che hai detto che non volevi fare!) O lanciare un'eccezione (dato che non puoi garantire l'integrità del transazione).

Quindi l'utilizzo di una proprietà DisablePromotion non avrebbe molto valore poiché, per l'applicazione non promuovere la transazione, è ancora necessario seguire le regole di escalation.

Se lo si desidera, è possibile gestire l'evento DistributedTransactionStarted e generare un'eccezione all'avvio di una transazione distribuita. Ciò garantirebbe che l'applicazione non stia utilizzando transazioni distribuite ma che probabilmente non è ciò che desideri.

+2

+1 per te Tuzo. Ben detto. –

+1

Se la transazione viene promossa perché si accede a due database, ma si sta solo * scrivendo * su un database, è possibile evitare la promozione attenuando la transazione quando si accede all'altro db. Ad esempio 'using (new TransactionScope (TransactionScopeOption.Suppress, new TransactionOptions {IsolationLevel = IsolationLevel.ReadUncommitted})) {// Accedi ad altro db}' –

2

Non credo ci sia un modo diretto per disattivare la promozione. Potresti voler esaminare le situazioni che fanno sì che una transazione venga promossa. Juval Lowy ha scritto un eccellente whitepaper (anche scaricabile here) interamente su System.Transactions. Egli copre le regole di promozione in dettaglio.

+0

È anche possibile trovare una versione HTML di Juval Lowy's Introducing System.Transactions all'indirizzo http://msdn.microsoft.com/en-us/library/ms973865.aspx –

+0

Eccellente carta bianca. Grazie mille. – Maarten

1

Sto usando il seguente codice con il servizio MSDTC disabilitato.

var txOpts = new TransactionOptions 
      { 
      IsolationLevel = IsolationLevel.ReadCommitted, 
      Timeout = TimeSpan.FromMinutes(10)}; 

using (var tx = new TransactionScope(TransactionScopeOption.Suppress, txOpts)) 
{ 
    using (var db1 = new ObjectContext(connection1)) 
    { 
    db1.Connection.Open(); 
    using (var db1tx = db1.Connection.BeginTransaction(
           System.Data.IsolationLevel.ReadCommitted)) 
    { 
     using (var db2 = new ObjectContext(connection2)) 
     { 
     db2.Connection.Open(); 
     using (var db2tx = db2.Connection.BeginTransaction(
          System.Data.IsolationLevel.ReadCommitted)) 
     { 
      // do stuff 

      db1.SaveChanges(false); 
      db2.SaveChanges(false); 

      db1tx.Commit(); 
      db2tx.Commit(); 
      tx.Complete(); 
     } 
     } 
    } 
    } 
}