Oracle
 sql >> Base de données >  >> RDS >> Oracle

SELECT FOR UPDATE empêche-t-il l'insertion d'autres connexions lorsque la ligne n'est pas présente ?

MySQL

SELECT ... FOR UPDATE avec UPDATE

En utilisant des transactions avec InnoDB (validation automatique désactivée), un SELECT ... FOR UPDATE permet à une session de verrouiller temporairement un enregistrement particulier (ou des enregistrements) afin qu'aucune autre session ne puisse le mettre à jour. Ensuite, au sein de la même transaction, la session peut effectivement effectuer une UPDATE sur le même enregistrement et valider ou annuler la transaction. Cela vous permettrait de verrouiller l'enregistrement afin qu'aucune autre session ne puisse le mettre à jour pendant que vous faites peut-être une autre logique métier.

Ceci est accompli avec le verrouillage. InnoDB utilise des index pour verrouiller les enregistrements, donc verrouiller un enregistrement existant semble facile - il suffit de verrouiller l'index de cet enregistrement.

SELECT ... FOR UPDATE avec INSERT

Cependant, pour utiliser SELECT ... FOR UPDATE avec INSERT , comment verrouiller un index pour un enregistrement qui n'existe pas encore ? Si vous utilisez le niveau d'isolement par défaut de REPEATABLE READ , InnoDB utilisera également gap serrures. Tant que vous connaissez l'id (ou même une plage d'identifiants) à verrouiller, alors InnoDB peut verrouiller l'espace afin qu'aucun autre enregistrement ne puisse être inséré dans cet espace jusqu'à ce que nous en ayons fini.

Si votre id était une colonne auto-incrémentée, puis SELECT ... FOR UPDATE avec INSERT INTO serait problématique car vous ne sauriez pas ce que le nouveau id était jusqu'à ce que vous l'insériez. Cependant, puisque vous connaissez le id que vous souhaitez insérer, SELECT ... FOR UPDATE avec INSERT fonctionnera.

MISE EN GARDE

Au niveau d'isolement par défaut, SELECT ... FOR UPDATE sur un enregistrement inexistant pas bloquer les autres transactions. Donc, si deux transactions font toutes les deux un SELECT ... FOR UPDATE sur le même enregistrement d'index inexistant, ils obtiendront tous les deux le verrou et aucune des transactions ne pourra mettre à jour l'enregistrement. En fait, s'ils essaient, un blocage sera détecté.

Par conséquent, si vous ne voulez pas faire face à un blocage, vous pouvez simplement procéder comme suit :

INSÉRER DANS ...

Démarrez une transaction et effectuez le INSERT . Faites votre logique métier et validez ou annulez la transaction. Dès que vous faites le INSERT sur l'index d'enregistrement inexistant sur la première transaction, toutes les autres transactions seront bloquées si elles tentent de INSERT un enregistrement avec le même index unique. Si la deuxième transaction tente d'insérer un enregistrement avec le même index après que la première transaction a validé l'insertion, elle obtiendra une erreur "clé en double". Manipulez en conséquence.

SÉLECTIONNER... VERROUILLER EN MODE PARTAGE

Si vous sélectionnez avec LOCK IN SHARE MODE avant le INSERT , si une transaction précédente a inséré cet enregistrement mais n'a pas encore été validée, le SELECT ... LOCK IN SHARE MODE bloquera jusqu'à ce que la transaction précédente soit terminée.

Donc, pour réduire le risque d'erreurs de clé en double, en particulier si vous maintenez les verrous pendant un certain temps tout en exécutant la logique métier avant de les valider ou de les annuler :

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Si aucun enregistrement n'est renvoyé, alors
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)