Tout d'abord, le verrouillage d'une table n'empêchera pas une autre session d'émettre SELECT
déclarations contre les données.
En Session 1, si je verrouille la table
SQL> lock table foo in exclusive mode;
Table(s) Locked.
Je peux alors démarrer la session 2 et interroger les données autant que je le souhaite
SQL> select * from foo;
COL1
----------
1
1
Dans Oracle, les rédacteurs ne bloquent pas les lecteurs, vous ne pouvez donc jamais empêcher une autre session d'interroger les données d'une table.
Il semble que ce que vous essayez d'implémenter soit un verrouillage pessimiste. Dans ce cas, plutôt que de verrouiller la table, vous faites un SELECT FOR UPDATE
qui verrouille l'entrée particulière que vous avez l'intention de traiter. Tant que toutes les autres sessions tentent également de faire un SELECT FOR UPDATE
(selon la version d'Oracle, ajouter éventuellement le SKIP LOCKED
qualificatif et/ou le WAIT
qualificatif). Cela verrouille la ligne spécifique que vous traitez et permet à la deuxième session de sélectionner une ligne ou un délai d'expiration différent ou de trouver qu'il n'y a pas de lignes à traiter en fonction des spécificités de l'implémentation. Cela n'implique pas de verrouiller la table.
La seule façon de libérer un verrou est que la session qui l'a acquis le libère (généralement en mettant fin à la transaction) ou que la session qui l'a acquis soit terminée. Si l'application cliente est toujours en cours d'exécution mais ne fait rien pour libérer le verrou ou mettre fin à la session, le verrou sera maintenu indéfiniment. Un administrateur de base de données devrait explicitement tuer la session, laisser la transaction revenir en arrière et libérer le verrou pour remettre le système en marche. Si l'application cliente cesse de fonctionner ou, au moins, cesse de répondre (je ne sais toujours pas exactement de quel scénario d'échec vous parlez), il est possible que l'activation de la détection de connexion morte (DCD) via le Paramètre 'SQLNET.EXPIRE_TIME' au niveau de la base de données amènerait la base de données à déterminer que le client ne répond pas et à tuer automatiquement la session, annulant la transaction et libérant le verrou.
S'il y a plusieurs sessions traitant des données, cependant, il est généralement préférable d'utiliser une certaine forme de verrouillage optimiste. Sinon, vous concevez un système qui nécessitera inévitablement que le DBA trouve et tue de toute urgence des sessions afin de faire fonctionner à nouveau les utilisateurs professionnels et qui nécessitera de plus en plus d'interventions au fur et à mesure qu'il sera occupé. Ce n'est pas quelque chose que les DBA aiment faire et ce dont les utilisateurs professionnels aiment se plaindre. Un simple schéma de verrouillage optimiste donnerait donc quelque chose comme
- Sélectionnez une clé à traiter et une sorte de date indiquant la dernière fois que la ligne a été mise à jour.
- Mettez à jour une colonne d'état sur "traitement" afin que d'autres sessions n'essaient pas de traiter cette même ligne.
- Traitez l'entrée dans votre application
- Lorsque vous avez terminé le traitement, mettez à jour les données à l'aide de la clé et de l'heure que vous avez sélectionnées à la première étape. Si vous mettez à jour 1 ligne, vous savez qu'aucune autre session n'a modifié les données en question depuis que vous l'avez sélectionnée. Si vous mettez à jour 0 lignes, vous savez qu'une autre session a modifié les données depuis que vous les avez sélectionnées.
Avec ce type d'architecture, il est relativement facile d'interroger la base de données pour voir quelles lignes sont en cours de traitement et, par exemple, d'avoir un travail qui remet la colonne d'état à "non traité" après un certain temps si le client n'a pas achevé. Il est relativement facile pour les autres sessions de choisir une ligne différente à traiter. Et c'est relativement sûr si, par exemple, l'application se fige pendant quelques heures, puis récupère car elle découvre juste une fois le traitement terminé qu'une autre session a déjà retraité la ligne.