IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PL/SQL Oracle Discussion :

Comment bloquer les Delete consécutives sur la même ligne?


Sujet :

PL/SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2010
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Mai 2010
    Messages : 36
    Par défaut Comment bloquer les Delete consécutives sur la même ligne?
    Bonjour,

    Dans une application métier développée par java/javascript, nous avons une fonctionnalité qui permet d'annuler un ticket déjà créé (un ticket ici représente un droit d'achat dont le montant est soustrait du solde client). Donc l'annulation d'un ticket, quand elle est acceptée, rétablit le solde client avec le montant du ticket qui a été déjà soustrait.
    Le problème c'est que pour des raisons de lenteur réseau, il se trouve que l'utilisateur clique sur le bouton annuler plusieurs fois et donc la requete d'annulation est envoyée plusieurs fois.
    Ces requêtes multiples d'annulation (processus), sur le même ticket, passent sans problème (selon comment c'est développé aujourd'hui) et font que le solde du client est rétabli plusieurs fois ce qui lui donne plus de ce qu'il doit. Exemple: si on annule un ticket de 100 euros alors qu'on arrive à cliquer 3 fois sur le bouton annuler (sachant que le bouton annuler doit disparaître de l'écran dès le premier clique) alors le solde du client est augmenté de 3 x 100 euros au lieu de 100 euros.

    Est ce que vous avez une idée de comment on peut verrouiller ce traitement de telle sorte qu'un seul process annulation puisse être exécuté?

    Voici en bas la procédure stockée Oracle appelée lors du clique sur le bouton annuler d'un ticket donné. Le p_num_bordereau est l'identifiant d'un ticket.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    Procedure annuler_ticket(p_num_bordereau IN VARCHAR2, NMES OUT NUMBER, LMES OUT VARCHAR2)
    Is
     
    V_ID_BORDEREAU NUMBER;
    v_montant Number;
    v_id_client number;
     
    Begin
     
    SELECT a.id_bordereau, montant, id_client
    INTO v_id_bordereau, v_montant, v_id_client
    FROM  chm.OPERATIONS a
    AND a.numero_bordereau = p_num_bordereau;
    --
    DELETE FROM chm.operations
    WHERE id_bordereau = v_id_bordereau;
    --
    Update chm.soldes set solde = solde + v_montant where id_client = v_id_client;
    --
    nmes := 0;
    lmes := 'OK';
    Exception
      When Others then
        nmes := 1;
        lmes := 'Ligne inexistante';
    End;

  2. #2
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    Normalement le second devrait sortir en erreur 1 : Ligne inexistante, sauf s'il s'agit de 2 sessions différentes et un commit lointain.


    Le mieux est de poser un verrou sur la ligne lors du SELECT, comme ça, tu es "sûr" que les autres sessions qui vont annuler le même p_num_bordereau vont attendre que le premier ait fini son commit


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    PROCEDURE annuler_ticket(p_num_bordereau IN VARCHAR2, NMES OUT NUMBER, LMES OUT VARCHAR2)
    IS
      v_id_bordereau number;
      v_montant number;
      v_id_client number;
    BEGIN
     
      SELECT a.id_bordereau, montant, id_client
      INTO v_id_bordereau, v_montant, v_id_client
      FROM chm.OPERATIONS a
      AND a.numero_bordereau = p_num_bordereau
      FOR UPDATE;
     
      DELETE chm.OPERATIONS
      WHERE id_bordereau = v_id_bordereau;
     
      UPDATE chm.soldes set solde = solde + v_montant
      WHERE id_client = v_id_client;
     
      nmes := 0;
      lmes := 'OK';
    EXCEPTION
    WHEN Others THEN
        nmes := 1; lmes := 'Ligne inexistante';
    END;
    Pourquoi le where du DELETE ne correspond pas au SELECT ? Tu DELETE plus de lignes ?
    Parce que du coup, le verrou sur 1 ligne et le DELETE sur plusieurs autres, tu peux avoir un interblocage, dans ce cas là, il faudrait poser un verrou NOWAIT sur toutes les lignes à DELETER
    Je ne met pas le code, mais je peux le fournir si tu en as besoin.

  3. #3
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    Le delete ne renvoit pas d'erreur lorsque la ligne n'est pas trouvée. Le nombre de lignes est dans SQL%ROWCOUNT
    Il faudrait gérer une transaction avec savepoint et rollback. Genre: savepoint; update ; delete ; rollback if rowcount=0;

  4. #4
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Pourquoi tu voudrais faire si compliqué avec des savepoint et un update avant le delete ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    DELETE ..
    IF sql%rowcount <> 0 THEN UPDATE END IF;
    Mais tout dépend si la condition where du SELECT est la même que le DELETE ou pas.

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 010
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 010
    Billets dans le blog
    6
    Par défaut
    Il suffit d'annuler la transaction si le nombre de ligne mis à jour dans la première requête est de zéro.

    C'est le B A BA de la gestion des transactions !

    1) pas de ligne mise à jour … que faire ?
    2) erreur lors de la mise à jour … que faire ?

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #6
    Membre Expert
    Homme Profil pro
    Chef de projet MOA
    Inscrit en
    Février 2012
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet MOA
    Secteur : Distribution

    Informations forums :
    Inscription : Février 2012
    Messages : 652
    Par défaut
    N'y a t-i pas un soucis dans la requête SELECT aussi ?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT a.id_bordereau, montant, id_client
      INTO v_id_bordereau, v_montant, v_id_client
      FROM chm.OPERATIONS a
      AND a.numero_bordereau = p_num_bordereau
    Sinon je rejoins les solutions à base de contrôle sur le SQL%ROWCOUNT qui doit aiguiller sur l'UPDATE ou non

  7. #7
    Expert confirmé
    Avatar de pachot
    Homme Profil pro
    Developer Advocate YugabyteDB
    Inscrit en
    Novembre 2007
    Messages
    1 822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Developer Advocate YugabyteDB
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 822
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par McM Voir le message
    Pourquoi tu voudrais faire si compliqué avec des savepoint et un update avant le delete ?
    Parce que je vois un affreux 'when others' et j'ai peur que des modifications faites à moitié soient ensuite commit-ées.
    Et que je trouve ça moins compliqué, de bien indiquer le début et la fin de ce qui est atomique. Et aussi de toucher au solde en premier.

Discussions similaires

  1. Réponses: 0
    Dernier message: 31/07/2014, 12h26
  2. Comment afficher une liste sur la même ligne avec tous les navigateurs
    Par Alexandrebox dans le forum Mise en page CSS
    Réponses: 1
    Dernier message: 25/07/2010, 03h05
  3. Réponses: 6
    Dernier message: 29/05/2008, 12h06
  4. Comment bloquer les photos sur mon site
    Par footeuse13 dans le forum Sécurité
    Réponses: 5
    Dernier message: 08/08/2007, 16h54
  5. Réponses: 3
    Dernier message: 07/02/2007, 17h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo