Il existe deux approches générales du verrouillage.
Tout d'abord, vous avez un verrouillage pessimiste. Dans cette approche, vous verrouillez la ligne (SELECT ... FOR UPDATE
) qui empêche quiconque de modifier la ligne. Ensuite, vous faites la UPDATE
. Lorsque vous validez votre modification, le verrou est libéré. Il n'est pas nécessaire dans ce cas d'avoir une colonne numéro de version/horodatage (du moins pour ne pas prendre en charge le verrouillage) et le code est relativement simple.
L'inconvénient du verrouillage pessimiste est que vous devez maintenir le verrou tout le temps qu'un utilisateur est assis sur une page susceptible de modifier des données. C'est techniquement très difficile si vous créez une application Web, car HTTP est un protocole sans état. La demande qui rend initialement la page obtiendrait normalement une connexion à partir du pool de connexions, faites le SELECT
, puis rétablissez la connexion au pool une fois la page terminée. La demande suivante de mise à jour des données se produirait généralement sur une connexion différente avec une session de base de données différente, vous ne pouvez donc pas verrouiller la ligne dans la première session et la mettre à jour dans la seconde. Si vous vouliez verrouiller la ligne de manière pessimiste, vous auriez besoin de faire beaucoup de travail sur le back-end pour vous assurer que la connexion à la base de données était liée à une session de niveau intermédiaire particulière jusqu'à ce que l'utilisateur ait fini de modifier les données. Cela a généralement des impacts très négatifs sur l'évolutivité et introduit toutes sortes de problèmes de gestion de session - comment savez-vous, par exemple, si j'ai demandé une page, verrouillé une ligne, puis fermé mon navigateur sans jamais me déconnecter ou faire un changement ? Combien de temps allez-vous laisser l'enregistrement verrouillé dans la base de données ? Que se passe-t-il si une autre session tente de verrouiller la ligne ? Combien de temps allez-vous laisser cette session bloquer l'attente d'un verrou si la première personne est sortie déjeuner ? En règle générale, les utilisateurs n'implémentent pas le verrouillage pessimiste dans les applications Web, car la gestion des sessions et de l'état des sessions est tout simplement trop peu pratique.
La deuxième option est le verrouillage optimiste. Dans cette approche, vous ajoutez un numéro de version/horodatage à la ligne. Vous sélectionnez ce numéro de version/horodatage lorsque vous interrogez les données. Ensuite, vous l'utilisez dans votre WHERE
clause lorsque vous effectuez ultérieurement la mise à jour et vérifiez combien de lignes ont été réellement modifiées. Si vous modifiez exactement une ligne, vous savez que la ligne n'a pas changé depuis que vous l'avez lue. Si vous modifiez 0 lignes, vous savez que la ligne a changé et vous pouvez gérer l'erreur.
Ainsi, par exemple, vous sélectionneriez les données avec le numéro de version
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
Lorsque vous étiez prêt à faire la mise à jour, vous feriez quelque chose comme ça où vous utilisez la version
dans votre UPDATE
et renvoie une erreur si la ligne a changé
UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
Votre application ferait alors quelque chose d'utile avec l'erreur. Normalement, cela signifierait faire quelque chose comme interroger à nouveau les données, présenter les modifications à l'utilisateur et lui demander s'il souhaite toujours appliquer ses modifications. Si, par exemple, je lis une adresse et que je commence à la modifier, que je vais déjeuner, que mon collègue se connecte, lit la même adresse, apporte quelques modifications et l'enregistre, puis que je reviens et que j'essaie d'enregistrer mes modifications, cela aurait généralement du sens pour me montrer quelque chose m'indiquant que mon collègue a déjà changé l'adresse en quelque chose de nouveau-- est-ce que je veux continuer à apporter des modifications ou est-ce que je veux les abandonner.