2009-04-06 24 views
14

abbiamo un problema con TransactionScope. TransactionScope ci offre un'ottima flessibilità per utilizzare le transazioni attraverso il nostro Data Access Layer. In questo modo possiamo utilizzare le transazioni implicite o esplicite. Ci sono alcuni miglioramenti delle prestazioni ancora transazioni ADO.NET, ma in questo momento questo non è davvero un problema. Tuttavia abbiamo problemi con il blocco. Nel codice di esempio riportato di seguito, sebbene il livello di isolamento sia impostato su ReadCommitted, non è possibile effettuare l'istruzione Select SQL da altri client sulla tabella testTable, fino a quando non verrà eseguito il commit della transazione principale (nel metodo Main), poiché il blocco sull'intera tabella. Abbiamo anche provato a utilizzare una sola connessione tra tutti i metodi, ma lo stesso comportamento. Il nostro DBMS è SQL Server 2008. C'è qualcosa che non abbiamo capito?TransactionScope and Isolation Level

saluti Anton Kalcik

Vedi questo codice di esempio:

class Program 
{ 
    public class DAL 
    { 
     private const string _connectionString = @"Data Source=localhost\fsdf;Initial Catalog=fasdfsa;Integrated Security=SSPI;"; 

     private const string inserttStr = @"INSERT INTO dbo.testTable (test) VALUES(@test);"; 

     /// <summary> 
     /// Execute command on DBMS. 
     /// </summary> 
     /// <param name="command">Command to execute.</param> 
     private void ExecuteNonQuery(IDbCommand command) 
     { 
      if (command == null) 
       throw new ArgumentNullException("Parameter 'command' can't be null!"); 

      using (IDbConnection connection = new SqlConnection(_connectionString)) 
      { 
       command.Connection = connection; 
       connection.Open(); 
       command.ExecuteNonQuery(); 
      } 
     } 

     public void FirstMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello1")); 

      using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       ExecuteNonQuery(command); 
       sc.Complete(); 
      } 
     } 

     public void SecondMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello2")); 

      using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       ExecuteNonQuery(command); 
       sc.Complete(); 
      } 
     } 
    } 

    static void Main(string[] args) 
    { 

     DAL dal = new DAL(); 
     TransactionOptions tso = new TransactionOptions(); 
     tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; 

     using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required,tso)) 
     { 
      dal.FirstMethod(); 
      dal.SecondMethod(); 
      sc.Complete(); 
     } 
    } 
} 

risposta

19

Non credo che il problema abbia a che fare con il concetto di .NET TransactionScope. Piuttosto, sembra che tu stia descrivendo il comportamento previsto delle transazioni di SQL Server. Inoltre, la modifica del livello di isolamento riguarda solo "letture dei dati" e non "scritture di dati". Da SQL Server BOL:.

"La scelta di un livello di isolamento delle transazioni non pregiudica i blocchi acquisiti per proteggere le modifiche dei dati Una transazione ottiene sempre un blocco esclusivo su eventuali dati che modifica e sostiene che il blocco fino al completamento della transazione, indipendentemente dal livello di isolamento impostato per quella transazione.Per le operazioni di lettura, i livelli di isolamento della transazione definiscono principalmente il livello di protezione dagli effetti delle modifiche apportate da altre transazioni. "

Ciò significa che si può evitare che il comportamento di blocco modificando il livello di isolamento per il cliente rilascia la SELECT statement (s). Il livello di isolamento READ COMMITED (predefinito) non impedirà il blocco. Per impedire il blocco del client, si utilizzerà il livello di isolamento READ UNCOMMITTED, ma si dovrebbe tenere conto della possibilità che i record possano essere recuperati che sono stati aggiornati/inseriti da una transazione aperta (cioè potrebbero andare via se la transazione viene ripristinata) .

+0

Grazie per il vostro suggerimento. Quindi, se capito bene, le impostazioni del livello di isolamento della transazione su TransactionScope influenzeranno solo il modo in cui sarò in grado di accedere ai dati mediante l'operazione di lettura su DBMS da questo ambito di transazione. –

9

Buona domanda per parlare di transazioni.

Il metodo principale consiste nel mantenere le transazioni in commit. Anche se ti impegni con altri metodi, avrai ancora blocchi su quella riga. Non sarai in grado di leggere quella tabella con READ COMMITTED, che è previsto, fino a quando non effettuerai il commit della tua transazione di blocco.

Ecco dopo metodo ritorna primi:

First method returns

Dopo rendimenti secondo metodo, si aggiungerà un altro blocco a tavola.

secont method returns

Se eseguiamo select da una finestra di query con SPID (55), si vedrà aspettare di stato.

select is waiting

Dopo aver principale metodo trans si impegna, si otterrà il risultato di selezione dichiarazione e mostrerà solo condiviso blocco dalla nostra pagina di query select.

Scope commits and select returns

X mezzi blocco esclusivo, IX blocchi preventivi. You can read more from my blog post about transactions.

Se si desidera leggere senza attendere, è possibile utilizzare nolock suggerimento. Se si desidera leggere dopo il commit del primo metodo, è possibile rimuovere tale ambito esterno.