Introduction à l'accès concurrentiel aux données dans ADO.NET

Mise à jour : novembre 2007

Lorsque plusieurs utilisateurs tentent de modifier des données en même temps, des contrôles sont nécessaires afin d'empêcher que les modifications d'un utilisateur ne compromettent celles des utilisateurs simultanés. Le système de gestion des événements ayant lieu dans cette situation est appelé contrôle d'accès concurrentiel.

Types de contrôles d'accès concurrentiel

D'une manière générale, il existe trois méthodes courantes permettant de gérer l'accès concurrentiel dans une base de données :

  • Contrôle d'accès concurrentiel pessimiste : une ligne n'est pas disponible pour les utilisateurs à partir du moment ou l'enregistrement est extrait et jusqu'à ce qu'il soit mis à jour dans la base de données.

  • Contrôle d'accès concurrentiel optimiste : une ligne n'est pas disponible pour les autres utilisateurs, pendant la mise à jour des données uniquement. Le processus de mise à jour examine la ligne dans la base de données et détermine si des modifications ont été effectuées. Si un utilisateur tente de mettre à jour un enregistrement ayant déjà subi des modifications, cela constitue une violation d'accès concurrentiel.

  • « Priorité aux dernières modifications » : une ligne n'est pas disponible pour les autres utilisateurs, pendant la mise à jour des données uniquement. Toutefois, les mises à jour ne sont pas comparées à l'enregistrement d'origine ; l'enregistrement est simplement écrit, remplaçant ainsi les éventuelles modifications apportées par d'autres utilisateurs depuis la dernière actualisation des enregistrements.

Accès concurrentiel pessimiste

L'accès concurrentiel pessimiste est généralement utilisé pour deux raisons. La première découle de l'existence, dans certaines situations, d'une forte contention pour les mêmes enregistrements. Le coût de la mise en place de verrous sur les données est inférieur à celui de la restauration des modifications en cas de conflits d'accès concurrentiel.

La seconde concerne les situations où il serait dommageable qu'un enregistrement soit modifié au cours d'une transaction. Une application de gestion des stocks en est un bon exemple. Prenons l'exemple d'un représentant d'une société vérifiant le stock pour un client potentiel. En général, vous souhaitez verrouiller l'enregistrement jusqu'à ce qu'une commande soit générée, ce qui entraîne en principe le passage de l'article à l'état commandé et supprime cet article du stock disponible. Si aucune commande n'est générée, le verrou sera levé de façon à permettre à d'autres utilisateurs vérifiant le stock d'obtenir un décompte précis du stock disponible.

Toutefois, le contrôle d'accès concurrentiel pessimiste ne peut pas être utilisé dans une architecture déconnectée. Les connexions ne restent ouvertes que le temps de lire les données ou de les mettre à jour. Les verrous ne peuvent donc pas être maintenus pendant des périodes prolongées. En outre, les applications qui utilisent des verrous pendant des périodes prolongées ne sont pas évolutives.

Accès concurrentiel optimiste

Dans la méthode d'accès concurrentiel optimiste, les verrous ne sont définis et maintenus que pendant l'accès à la base de données. Ils empêchent les autres utilisateurs de mettre à jour des enregistrements au même moment. Les données sont toujours disponibles, sauf au moment précis d'une mise à jour. Pour plus d'informations, consultez Accès concurrentiel optimiste (ADO.NET).

Lors d'une tentative de mise à jour, la version d'origine d'une ligne modifiée est comparée à la ligne existante de la base de données. Si ces deux lignes sont différentes, la mise à jour échoue en raison d'une erreur d'accès concurrentiel. Il vous appartient alors, à ce stade, de rapprocher les deux lignes, à l'aide de votre logique métier.

Priorité aux dernières modifications

Avec cette méthode, les données d'origine ne sont pas vérifiées et la mise à jour est simplement écrite dans la base de données. Le scénario suivant peut ainsi se produire :

  • L'utilisateur A extrait un enregistrement de la base de données.

  • L'utilisateur B extrait ce même enregistrement, le modifie en le mettant à jour dans la base de données.

  • L'utilisateur A modifie « l'ancien » enregistrement en le mettant à jour dans la base de données.

Dans le scénario ci-dessus, les modifications apportées par l'utilisateur B n'ont jamais été vues par l'utilisateur A. Assurez-vous qu'une telle situation est acceptable si vous envisagez d'utiliser l'approche Priorité aux dernières modifications du contrôle de l'accès concurrentiel.

Contrôle de l'accès concurrentiel dans ADO.NET et Visual Studio

ADO.NET et Visual Studio utilisent l'accès concurrentiel optimiste, car l'architecture de données se base sur les données déconnectées. Il vous faut donc ajouter une logique métier pour résoudre les problèmes liés à l'accès concurrentiel optimiste.

Si vous optez pour l'accès concurrentiel optimiste, il existe deux approches générales pour déterminer si des modifications ont eu lieu : l'approche basée sur la version (horodateurs ou numéros de version véritables) et l'approche basée sur l'enregistrement de toutes les valeurs.

Approche considérant le numéro de version

Dans cette approche, l'enregistrement à mettre à jour doit posséder une colonne contenant un horodatage ou un numéro de version. L'horodatage ou le numéro de version est enregistré sur le client lors de la lecture de l'enregistrement. Cette valeur est ensuite intégrée à la mise à jour.

L'une des méthodes permettant de gérer l'accès concurrentiel consiste à n'effectuer de mise à jour que si la valeur de la clause WHERE correspond à la valeur de l'enregistrement. La représentation SQL de cette approche est la suivante :

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE DateTimeStamp = @origDateTimeStamp

La comparaison peut également être effectuée à l'aide du numéro de version :

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE RowVersion = @origRowVersionValue

Si les horodatages ou les numéros de version correspondent, cela signifie que l'enregistrement du magasin de données n'a pas été modifié et qu'il peut donc être mis à jour avec les nouvelles valeurs du groupe de données en toute sécurité. S'ils ne correspondent pas, une erreur est retournée. Vous pouvez écrire du code pour implémenter ce type de vérification de l'accès concurrentiel dans Visual Studio. Vous devez également écrire du code pour répondre à tout conflit de mise à jour. Pour garantir l'exactitude de l'horodatage ou du numéro de version, vous devez définir un déclencheur dans la table afin de mettre à jour cet horodatage ou numéro lorsqu'une ligne est modifiée.

Approche basée sur l'enregistrement de toutes les valeurs

L'obtention de copies de tous les champs lors de la lecture de l'enregistrement constitue une méthode alternative à celle qui consiste à utiliser l'horodatage ou le numéro de version. L'objet DataSet dans ADO.NET conserve deux versions de chaque enregistrement modifié : une version d'origine (initialement lue dans la source de données) et une version modifiée, qui représente les mises à jour des utilisateurs. Lors de la tentative de réécriture de l'enregistrement dans la source de données, les valeurs d'origine de la ligne de données sont comparées à celles de l'enregistrement de la source de données. S'ils correspondent, cela signifie que l'enregistrement de la base de données n'a pas été modifié depuis sa lecture. Dans ce cas, les valeurs modifiées du groupe de données sont écrites avec succès dans la base de données.

Chaque commande d'adaptateur de données possède une collection de paramètres pour chacune de ses quatre commandes (DELETE, INSERT, SELECT et UPDATE). Chaque commande possède des paramètres pour les valeurs d'origine et les valeurs actuelles (ou modifiées).

Remarque :

L'ajout d'enregistrements (commande INSERT) ne requiert que les valeurs actuelles puisqu'il n'existe aucun enregistrement d'origine ; la suppression d'enregistrements (commande DELETE) ne requiert que les valeurs d'origine pour rechercher les enregistrements à supprimer.

L'exemple suivant montre le texte de la commande pour un groupe de données mettant à jour une table Customers classique. La commande est spécifiée pour le langage SQL dynamique et l'accès concurrentiel optimiste.

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
       ContactTitle = currContactTitle, Address = @currAddress, City = @currCity, 
       PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
      AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL) 
      AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
       PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)

Notez que les neuf paramètres de l'instruction SET représentent les valeurs actuelles qui seront écrites dans la base de données, alors que les neuf paramètres de l'instruction WHERE représentent les valeurs d'origine utilisées pour rechercher l'enregistrement d'origine.

Les neuf premiers paramètres de l'instruction SET correspondent aux neuf premiers paramètres de la collection de paramètres. La propriété SourceVersion de ces paramètres a la valeur Current.

Les neuf paramètres suivants de l'instruction WHERE sont utilisés pour l'accès concurrentiel optimiste. Ces espaces réservés correspondent aux neuf paramètres suivants de la collection de paramètres et la propriété SourceVersion de chacun de ces paramètres a la valeur Original.

L'instruction SELECT est utilisée pour actualiser le groupe de données après la mise à jour. Cette instruction est générée lorsque vous définissez l'option Actualiser le DataSet dans la boîte de dialogue Options de génération SQL avancées.

Remarque :

L'instruction SQL ci-dessus utilise des paramètres nommés, alors que les commandes OleDbDataAdapter utilisent des points d'interrogation (?) comme espaces réservés de paramètres.

Par défaut, Visual Studio crée automatiquement ces paramètres si vous sélectionnez l'option Accès concurrentiel optimiste dans l'Assistant Configuration d'adaptateur de données. Il vous appartient d'ajouter du code pour gérer les erreurs en fonction des besoins de votre entreprise. ADO.NET fournit un objet DBConcurrencyException retournant la ligne qui enfreint les règles d'accès concurrentiel. Pour plus d'informations, consultez Comment : gérer les erreurs d'accès concurrentiel.

Voir aussi

Tâches

Comment : gérer les erreurs d'accès concurrentiel

Concepts

Accès concurrentiel optimiste (ADO.NET)

Référence

DBConcurrencyException