Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour (de prime abord j'étais tenté de poster dans la partie BDD, mais il s'agit bien de coding PB, alors...)
Sous Powerbuilder 9 avec base de données SQL Server 2000, je souhaite gérer les deadlocks ; j'ai donc mis en place une bidouille de ce type, mais apparemment, le deadlock outrepasse la boucle :
If maDtw.Update(True, False) <> 1 Then ROLLBACK USING SQLCA; MessageBox(gAppNom, "L'erreur suivante s'est produite :~r" + SQLCA.SQLErrText, StopSign!, Ok!) return FALSE End If li_essai = 10 Do COMMIT USING SQLCA; If SQLCA.SQLDBCode <> 0 Then If li_essai = 0 Then ROLLBACK USING SQLCA; MessageBox(gAppNom, "Impossible d'enregistrer la transaction. Contactez le service informatique.", StopSign!) Return False End If lb_ok = False MessageBox(gAppNom, "Une erreur SQL est survenue :~r" + SQLCA.SQLErrText + ".~rL'opération va être retentée (" + String(li_essai) + ").", Exclamation!) li_essai -- If maDtw.Update(True, False) <> 1 Then ROLLBACK USING SQLCA; MessageBox(gAppNom, "Erreur lors de la suppression de la liste de pilotage :~r" + SQLCA.SQLErrText, StopSign!, Ok!) return FALSE End If Else lb_ok = True End If Loop Until lb_ok
Dernière modification par sbouvetJD (09-08-2010 12:05:05)
Hors ligne
bonjour,
Pour moi je vois plusieurs erreurs.
Si ton erreur survient sur <If maDtw.Update(True, False) <> 1 Then> comme tu effectue un return False tu ne pourras jamais rentrer dans la boucle
En deux quand tu rentre dans ta boucle tu effectue un commit lequel vas mettre le sqldbcode à 0 donc tu vas passer dans le else et tu remet ton booleen à true donc tu sort de la boucle.
Cdt
Yanis
Hors ligne
Bonjour sbouvetJD,
Apparemment tu ne sais pas ce qu'est un deadlock, sinon tu n'aurai jamais écris ".. il s'agit bien de coding PB.."
Les deadlocks sont un problème complexe, et c'est pas avec une bidouille que tu vas t'en sortir.
La première chose à faire c'est de diagnostiquer.
Un deadlock ne se fait pas tout seul, il implique toujours au moins 2 transactions.
Tu trouveras l'info dans les logs de ton serveur SQL.
Quels sont les 2 programmes qui se sont interbloqués ?
Sur ta bidouille :
maDtw est parfois une datawindow, parfois un tableau de datawindow.
Combien de dw sont impliquées dans ta transaction ?
Si tu en as une seule, autant rester en autocommit
Hors ligne
shahin :
Désolé pour le tableau de DTW, erreur de copier/coller sur le forum.
Un deadlock, dans mon cas, est apparemment l'accès concurrentiel à une ressource commune par au moins 3 points ; concrètement, notre applicatif (jusqu'à 16 postes en simultané, + triggers et tâches régulières annexes) effectue des UPDATE / DELETE sur une même table. C'est du moins la seule hypothèse qui nous a semblée plausible.
Yanis :
Si l'ordre d'update me retourne une erreur (duplicate key par exemple ou non respect d'une clef étrangère), j'effectue immédiatement mon rollback.
En fait je pensais que le COMMIT USING SQLCA me retournerait un DBCODE <> 0 si le serveur provoque une erreur comme un deadlock, mais d'après ce que vous semblez me dire, c'est l'UPDATE() qui me retourne l'info ?
Hors ligne
Salut,
Je pense que dans le cas d'un deadlock ton UPDATE doit te retourner une erreur. Dans ce cas il serait possible de tester le sqldbcode = 1205 ( je crois que c'est la valeur retourné en cas de deadlock ) à ce moment là j'exécuterai la boucle. ( en n'effectuant pas de commit au départ comme tu l'as fait )
Si la fonction update ne te retourne pas d'erreur ( ce qui pour moi serait un bug ) je testerai la valeur du sqlcode pour savoir si une erreur est survenue et si oui je testerai le sqldbcode ( 1205) pour savoir si j'avais un deadlock.
Cdt
Yanis
Hors ligne
Je vous ai présenté une version simplifiée de mon problème, car, en fait, lorsque je simule un deadlock et que j'exécute mon code au pas à pas, c'est bien sur la ligne du COMMIT que le deadlock est provoqué. En effet, dans mon commit, j'ai plusieurs datawindows que j'UPDATE() (ce qui déclenche update ou delete selon le cas) + SQL Embedded. A chaque tentative d'UPDATE(), si l'ordre est <> 1, je retourne le message d'erreur DB associé. Lorsque je tente le COMMIT, c'est donc ma transaction qui est deadlockée, et qui peut comporter donc plusieurs ordres SQL. Je me dois donc de retenter l'ensemble de ma transaction et non pas seulement l'update de maDtw. Pour dire, je stocke mon embedded dans un tableau de chaîne et je retente les ordres par un
PREPARE SQLSA FROM :ls_sql USING SQLCA; EXECUTE SQLSA USING :ll_temp;
Hors ligne
salut,
Est tu sur que c'est ton commit qui reçoit ton deadlock. (Je n'ai jamais vu celà )
Explication. Un verrou ( lock ) est posé par les ordres de maj Insert, Update, delete ou avec 1 ordre select en fonction du niveau d'isolation. Si l'ordre sql ne peut aboutir ( enregistrement en cours de modif par exemple ) et que celui qui te bloque essaye d'atteindre une ligne que toi tu bloque alors il y a deadlock. Si tous tes ordres sont bien passés ( ce que tu semble indiqué ) le commit est là pour retirer les verrous
Est tu sur qu'avant de faire le commit ton sqldbcode n'était pas déjà <> 0 ( j'ai déjà eu un cas mais je ne me souvient plus lequel ou le sqlcode était à 0 tout s'est bien passé et que le sqldbcode n'avait pas été réinitialisé par l'objet transaction).
Cdt
Yanis
Hors ligne
Me conseillez-vous, du coup, un programming du type :
ll_essai = 10 Do If maDtw.Update(True, False) <> 1 Then ll_sqldbcode = SQLCA.SQLDBCode ROLLBACK USING SQLCA; If sqldbcode = 1205 Then // DBCode POUR DEADLOCK If ll_essai = 0 Then MessageBox("", "Impossible d'enregistrer, verrou") Return 1 Else MessageBox("", "Verrou temporaire, autre tentative") ll_essai -- End If Else MessageBox("", "L'erreur suivante s'est produite :~r" + SQLCA.SQLErrText) Return 1 End If End If Loop Until SQLCA.SQLDBCode = 0 COMMIT USING SQLCA;
Hors ligne
Salut,
je ne me baserais pas sur le sqldbcode pour finir ma boucle
boolean lb_fin ll_essai = 10 Do If maDtw.Update(True, False) = 1 Then lb_fin = true Else ll_sqldbcode = SQLCA.SQLDBCode // Attention ici tu fais un rollback mais si tu as fait des MAJ // avec du sql embeded tu perd tes modif et tu continue à mettre à jour ta datawindow // si tu as eu un dead lock sur la fonction update. ????? ROLLBACK USING SQLCA; If sqldbcode = 1205 Then // DBCode POUR DEADLOCK If ll_essai = 0 Then MessageBox("", "Impossible d'enregistrer, verrou") Return 1 Else MessageBox("", "Verrou temporaire, autre tentative") ll_essai -- End If Else MessageBox("", "L'erreur suivante s'est produite :~r" + SQLCA.SQLErrText) Return 1 End If End If Loop Until lb_fin COMMIT USING SQLCA;
Hors ligne
Par contre je n'arrive plus à générer un deadlock pour tests ? Il me semblait qu'à l'époque j'avais bidouillé une SP qui faisait un ROLLBACK, mais cela ne semble pas affecter mon problème. Dans mon hypothèse, on a la configuration suivante :
POSTE_1 UPDATE sur maTABLE (enr. N°1)
POSTE_2 UPDATE sur maTABLE (enr. N°2)
POSTE_1 DELETE sur maTABLE (enr N°1)
POSTE_2 DELETE SUR maTABLE (enr N°2) -> DEADLOCK
C'est possible ? Sachant qu'UPDATE et DELETE passent en deux maDtw.Update() différents, et son COMMITés à la fin si tout va bien.
Dernière modification par sbouvetJD (10-08-2010 09:39:29)
Hors ligne
Pour moi un rollback n'a jamais généré de dealock au contraire puisqu'il enlève les lock posés dans la base par ta proc
Si tu veut faire un deadlock, je te conseille de prendre un outil tel que ISQL
1 > Tu met à jour avec ISQL ( tu dois choisr le bon enregistrement qui doit bloquer ton appli ) (tu n'es pas obligé de faire des modif tu peut faire un update avec les mêmes valeurs que celle contenue en base)
2 > Tu met à jour avec ton appli ( elle doit au moins mettre à jour une ligne et se retrouver bloquer par le verrou poser avec ISQL
3 > Tu essaye de mettre à jour avec ISQL l'enregistrement qui a été mis à jour par ton appli
Là tu as un cas de deadlock
Hors ligne
Question, à part cependant : le SQLCA.SQLErrText n'est-il pas réinitialisé après le ROLLBACK ? Dois-je le stocker ?
If maDtw.Update(True, False) <> 1 Then ErrMsg = SQLCA.SQLErrText ROLLBACK USING SQLCA; Messagebox("", ErrMsg) // Peut-on mettre directement Messagebox("", SQLCA.SQLErrText) End If
Hors ligne
je pense que tu as tout intérêt à le récupérer avant ton rollback
Hors ligne