Bonjour,
Je dois modifier une application Delphi/Interbase pour qu'elle fonctionne avec SQL Serveur 2008.
J'ai des tables qui utilisent des auto-incréments.
L'application fonctionne de la manière suivante :
- une table mémoire (ClientDataSet) ouvre une requête SQL pour récupérer les enregistrements puis ferme cette requête
- lors d'un ajout dans la table mémoire, une requête INSERT est envoyée au serveur
- lors d'une modification dans la table mémoire, une requête UPDATE est envoyée au serveur
- lors d'une suppression dans la table mémoire, une requête DELETE est envoyée au serveur.
Mon problème se situe au niveau d'un traitement par lots de génération de factures avec table en-tête de facture et table détail de facture.
Avec Interbase, à l'ajout d'un enregistrement dans la table mémoire je récupérais la prochaine valeur d'auto-incrément grâce à un générateur d'Interbase.
J'obtenais donc la valeur de l'auto-incrément AVANT de réaliser un INSERT et je pouvais donc créer les enregistrements de la table détail sans problème.
Pour connaître le principe que j'utilisais avec Interbase lire l'article de SQL Pro Clefs auto incrémentées paragraphe "4. Les mécanismes internes aux SGBDR".
J'ai étudié avec attention l'article de SQL Pro Auto incrément IDENTITY avec SQL server mais les solutions "@@IDENTITY", "SCOPE_IDENTITY()" et "IDENT_CURRENT(‘nom_table‘)" ne me conviennent pas puisqu'elles me permettent de connaître la valeur de l'auto-incrément APRES le INSERT ce qui m'oblige à rafraîchir la table mémoire ce qui est inacceptable dans le cas de mon application.
J'ai donc appliqué le principe "3.2. La solution : une table des clefs" de l'article de SQL Pro Clefs auto incrémentées qui me semblait parfaitement adapté.
Voici la procédure que j'ai créée :
Cette procédure fonctionnait très bien jusqu'à ce que je mette l'application dans des conditions réelles c'est-à-dire générer depuis 2 postes clients des factures par lots : 1000 factures sur chaque poste en même temps.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE P_PROCHAIN_ID -- Paramètre nom de la table dont on veut le prochain ID @NOM_TABLE VARCHAR(128), @ID INTEGER OUTPUT AS BEGIN -- Initialisation SET NOCOUNT ON; -- Déclarer un entier DECLARE @vNombre INTEGER SET @vNombre = 0 -- Initialiser le résultat SET @ID = -1 -- Démarrer la transaction SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION PROCHAIN_ID -- Vérifier si la table T_INCREMENT existe SELECT @vNombre = COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='T_INCREMENT' -- Créer la table T_INCREMENT si elle n'existe pas IF @vNombre = 0 BEGIN CREATE TABLE T_INCREMENT ( INC_TABLE VARCHAR(128) NOT NULL PRIMARY KEY, INC_VALEUR INTEGER NOT NULL DEFAULT 0 ) END -- Vérifier si la table demandée est présente dans T_INCREMENT SET @vNombre = 0 SELECT @vNombre = COUNT(*) FROM T_INCREMENT WHERE INC_TABLE = @NOM_TABLE -- Insérer la table demandée si elle n'est pas présente dans T_INCREMENT IF @vNombre = 0 BEGIN INSERT INTO T_INCREMENT (INC_TABLE, INC_VALEUR) VALUES (@NOM_TABLE, 0) END -- Calculer le prochain incrément SELECT @ID = INC_VALEUR + 1 FROM T_INCREMENT WHERE INC_TABLE = @NOM_TABLE -- Mettre à jour le nouvel incrément de la table demandée dans T_INCREMENT UPDATE T_INCREMENT SET INC_VALEUR = @ID WHERE INC_TABLE = @NOM_TABLE -- Terminer la transaction COMMIT TRANSACTION PROCHAIN_ID -- Finalisation SET NOCOUNT OFF END GO
J'obtiens systématiquement, à un moment ou à un autre, l'erreur "La transaction (ID de processus XX) a été bloquée sur les ressources verrou par un autre processus et a été choisie comme victime.".
Après réflexion, je comprends effectivement le "blocage"...
Il semble que l'application A cherche la lire la valeur du prochain auto incrément au moment au l'appli B "verrouille" cette table pour la mettre à jour par exemple.
Mais je ne trouve pas de solution et tourne en rond malgré la lecture de nombreux articles !!!
Merci à vous pour votre aide
Partager