Question

Nous avons une demande qui a été écrit à l'origine comme une application de bureau, voici il y a ces nombreuses années. Il commence une transaction à chaque fois que vous ouvrez un écran d'édition et commits si vous cliquez sur OK, ou si vous Annule cliquez sur Annuler. Cela a bien fonctionné pour une application de bureau, mais maintenant, nous essayons de passer à ADO.NET et SQL Server, et les transactions longues sont problématiques.

Je trouve que nous avons un problème lorsque plusieurs utilisateurs essaient tous de modifier (différents sous-ensembles de) la même table en même temps. Dans notre ancienne base de données, la transaction de chaque utilisateur acquerrait des verrous au niveau record à chaque enregistrement, ils modifiés au cours de leur opération; puisque les différents utilisateurs éditaient dossiers différents, tout le monde obtient leur propre serrures et tout fonctionne. Mais dans SQL Server, dès qu'un utilisateur modifie un enregistrement dans une transaction, SQL Server semble obtenir un verrou sur la table entière . Quand un second utilisateur essaie de modifier un record différent dans la même table , la seconde application de l'utilisateur verrouille tout simplement, parce que les blocs de SqlConnection jusqu'à ce que le premier utilisateur soit ou annule.

Je suis conscient du fait que des transactions longues sont mauvaises, et je sais que le meilleur solution serait de changer ces écrans de sorte qu'ils ne conservent plus les transactions ouvertes pendant une longue période. Mais puisque cela signifierait des changements invasives et risquées, je veux aussi faire des recherches s'il y a un moyen d'obtenir ce code et en cours d'exécution en l'état, juste pour que je sais quelles sont mes options.

Comment puis-je obtenir deux transactions des utilisateurs différents dans SQL Server pour verrouiller les dossiers individuels au lieu de la table entière?

Voici une application console rapide et sale qui illustre la question. J'ai créé une base de données appelée « test1 », avec une table appelée « valeurs » qui a juste ID (int) et les colonnes Valeur (nvarchar). Si vous exécutez l'application, il demande une carte d'identité de modifier, démarre une transaction, modifie cet enregistrement, et laisse alors la transaction ouverte jusqu'à ce que vous appuyez sur ENTRER. Je veux être en mesure de

  1. démarrer le programme et lui dire la mise à jour ID 1;
  2. laissez obtenir sa transaction et modifier l'enregistrement;
  3. commencer une deuxième copie du programme et lui dire la mise à jour ID 2;
  4. l'ont pu mettre à jour (et commit), alors que la transaction de la première application est toujours ouverte.

Actuellement, il se fige à l'étape 4, jusqu'à ce que je vais revenir à la première copie de l'application et la fermer ou appuyez sur ENTRÉE il engage. L'appel à des blocs command.ExecuteNonQuery jusqu'à ce que la première connexion est fermée.

public static void Main()
{
    Console.Write("ID to update: ");
    var id = int.Parse(Console.ReadLine());
    Console.WriteLine("Starting transaction");
    using (var scope = new TransactionScope())
    using (var connection = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test1;Integrated Security=True"))
    {
        connection.Open();
        var command = connection.CreateCommand();
        command.CommandText = "UPDATE [Values] SET Value = 'Value' WHERE ID = " + id;
        Console.WriteLine("Updating record");
        command.ExecuteNonQuery();
        Console.Write("Press ENTER to end transaction: ");
        Console.ReadLine();
        scope.Complete();
    }
}

Voici quelques choses que je l'ai déjà essayé, sans changement de comportement:

  • Modification du niveau d'isolation de transaction "read uncommitted"
  • Spécification d'un "AVEC (ROWLOCK)" sur l'instruction UPDATE
Était-ce utile?

La solution

Il suffit de vérifier, mais avez-vous une clé primaire ou un index unique sur la colonne ID?

Autres conseils

Regardez dans optimistes par rapport à verrouillage pessimiste.

Edit: Article précédent lié à ado classique ... désolé.

http://msdn.microsoft.com/ fr-fr / bibliothèque / cs6hb8k4 (VS.71) .aspx

Probablement l'indice a été créé avec verrous de ligne réglé sur « off ».
« AVEC (ROWLOCK) » dans une requête aurait aucun effet dans ce cas.

Vous pouvez les faire demi-tour avec ALTER INDEX , par exemple :

ALTER INDEX [PK_Values] ON [Values] SET (ALLOW_ROW_LOCKS = ON)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top