2009-04-06 7 views
14

nous avons un problème à utiliser TransactionScope. TransactionScope nous offre une très bonne flexibilité pour utiliser les transactions sur notre couche d'accès aux données. De cette façon, nous pouvons utiliser des transactions implicites ou explicites. Il y a encore une amélioration des performances des transactions ADO.NET, mais pour le moment ce n'est pas vraiment un problème. Cependant nous avons un problème avec le verrouillage. Dans l'exemple de code ci-dessous, bien que le niveau d'isolement soit défini sur ReadCommitted, il est impossible de faire une instruction Select SQL depuis un autre client sur la table testTable, jusqu'à ce que la transaction principale (dans la méthode Main) soit validée. Nous avons également essayé d'utiliser une seule connexion pour toutes les méthodes, mais le même comportement. Notre SGBD est SQL Server 2008. Y at-il quelque chose que nous n'avons pas compris?TransactionScope et niveau d'isolement

Cordialement Anton Kalcik

Voir cet exemple de code:

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

Répondre

19

Je ne pense pas que votre question n'a rien à voir avec le concept TransactionScope .NET. Au contraire, il semble que vous décrivez le comportement attendu des transactions SQL Server. En outre, la modification du niveau d'isolement n'affecte que les "lectures de données" et non les "écritures de données". A partir de SQL Server BOL.

« Le choix d'un niveau d'isolation de transaction ne modifie pas les verrous acquis pour protéger les modifications de données Une transaction obtient toujours un verrou exclusif sur toutes les données qu'il modifie et maintient ce verrou jusqu'à ce que la transaction est terminée, quel que soit le niveau d'isolement défini pour cette transaction Pour les opérations de lecture, les niveaux d'isolation des transactions définissent principalement le niveau de protection contre les effets des modifications effectuées par d'autres transactions. "

Qu'est-ce que cela signifie est que vous pouvez empêcher le comportement de blocage en changeant le niveau d'isolement pour le client de faire la déclaration SELECT (s). Le niveau d'isolement READ COMMITED (par défaut) n'empêchera pas le blocage. Pour éviter de bloquer le client, vous devez utiliser le niveau d'isolement READ UNCOMMITTED, mais vous devez tenir compte de la possibilité de récupérer des enregistrements qui ont été mis à jour/insérés par une transaction ouverte (ils peuvent disparaître si la transaction est annulée) .

+0

Merci pour votre indice. Donc, si cela est bien compris, les paramètres du niveau d'isolation des transactions sur TransactionScope n'affecteront que la façon dont je pourrai accéder aux données par opération de lecture sur le SGBD à partir de cette portée de transaction. –

9

Bonne question pour parler des transactions.

Votre méthode principale consiste à conserver les transactions à valider. Même si vous vous engagez dans d'autres méthodes, vous aurez toujours des verrous sur cette ligne. Vous ne pourrez pas lire cette table avec READ COMMITTED, ce qui est attendu, jusqu'à ce que vous validiez votre transaction de verrouillage.

Voici après première méthode retourne:

First method returns

Après la deuxième retour de la méthode, vous ajouter une serrure à table.

secont method returns

Si nous exécutons instruction select d'une fenêtre de requête avec SPID (55), vous verrez attendre l'état.

select is waiting

Une fois la méthode principale trans commits, vous obtiendrez le résultat de l'instruction select et il ne montrera partagé verrouillage de notre sélection page de requête de déclaration.

Scope commits and select returns

X signifie verrou exclusif, IX verrous d'intention. You can read more from my blog post about transactions.

Si vous voulez lire sans attendre, vous pouvez utiliser nolock hint. Si vous souhaitez lire après la validation de la première méthode, vous pouvez supprimer cette étendue externe.

Questions connexes