Le Table I/OOpérations de lecture, écriture ou mise à jour effectuées directement sur les tables de la base de données. standard des Event Rules (ER)Langage de programmation visuel propriétaire utilisé dans JD Edwards pour définir la logique métier. est suffisant pour les applications interactives à faible volume, mais il échoue sous des charges de travail à haute concurrence. Lorsque vous avez 50 à 100 threadsUnités d'exécution simultanées au sein d'un même processus informatique. simultanés provenant d'appels AIS OrchestratorComposant JDE permettant d'automatiser des processus et d'exposer des services via des API REST. rapides ou d' UBEsUniversal Batch Engine, les processus de traitement par lots ou rapports dans JD Edwards. multi-threadés accédant aux mêmes tables personnalisées F55, l'absence de contrôle explicite du verrouillage des enregistrements dans les ER entraîne des lectures incohérentes (dirty reads)Lecture de données modifiées par une autre transaction mais pas encore validées. et des violations de clé primaire. Pour éviter la corruption des données, les développeurs doivent dépasser les ER de base et implémenter un pattern JDE BSFNBusiness Function, un module de code (souvent en C) exécutant une logique métier spécifique dans JDE. Table IO strict en C pour lire et mettre à jour les tables personnalisées en toute sécurité.
En déplaçant cette logique vers une BSFN en C, vous pouvez utiliser des APIsInterface de programmation permettant à différents logiciels de communiquer entre eux. comme JDB_FetchForUpdate à l'intérieur de limites de transactionGroupe d'opérations de base de données traitées comme une seule unité logique (tout ou rien). explicites. Cela garantit qu'un enregistrement est verrouillé au niveau de la base de données du moment où il est lu jusqu'à l'exécution de JDB_CommitTransaction ou JDB_RollbackTransaction. D'après notre expérience, le remplacement des mises à jour ER standard par ce pattern dans les interfaces à haut volume réduit les blocages (deadlocks)Situation où deux processus s'attendent mutuellement, bloquant indéfiniment le système. de base de données de 70 % à 80 %, garantissant que vos tables personnalisées JDE 9.2 maintiennent une intégrité absolue des données.
Le risque des mises à jour de table non verrouillées dans JDE
Dans les environnements à haut débit, s'appuyer sur le Table I/O standard des Event Rules (ER) pour les mises à jour est un risque. Prenons l'exemple d'une table d'allocation d'inventaire personnalisée, F55101, gérant 100 à 200 sessions AIS simultanées poussant des commandes depuis une plateforme e-commerce externe. Lorsque deux sessions HTML parallèles récupèrent le même enregistrement F55101 simultanément, les deux lisent le même solde de départ, calculent leurs allocations respectives et écrivent en retour. La seconde écriture écrase silencieusement la première, provoquant un échec de concurrence classique de type "le dernier gagne" (last-in-wins) qui corrompt votre registre de stock physique.
Le Table I/O standard de JDE dans les Event Rules utilise par défaut une concurrence optimisteStratégie supposant que les conflits sont rares, ne verrouillant les données qu'au moment de l'écriture. sans verrouillage au niveau de la base de données. Dans un environnement de noyau CallObjectProcessus serveur JDE responsable de l'exécution de la logique métier (BSFN). multi-threadé, ce manque de protection conduit à une corruption immédiate des données sous un volume transactionnel lourd. Les développeurs supposent souvent que le middlewareLogiciel intermédiaire qui fait le lien entre différentes applications ou couches système. de base de données JDE gère cela automatiquement, mais les instructions Update des ER standard s'exécutent comme des opérations SQLLangage standard utilisé pour communiquer avec les bases de données relationnelles. détachées. Sans verrou actif, il n'y a aucune protection contre un autre thread modifiant la ligne dans la fenêtre de millisecondes entre vos étapes de lecture et de mise à jour.
Pour éliminer ces situations de compétition (race conditionsProblème survient lorsque le résultat dépend de l'ordre imprévisible d'exécution de plusieurs threads.) et ces lectures incohérentes, vous devez implémenter un verrouillage explicite des enregistrements à l'aide des APIs au niveau de la base de données. Un pattern de mise à jour sécurisé nécessite d'envelopper à la fois les opérations de lecture et de mise à jour dans une seule limite de transaction de base de données atomiquePropriété garantissant qu'une série d'opérations s'exécute entièrement ou pas du tout.. En utilisant JDB_FetchForUpdate à l'intérieur d'une limite de transaction manuelle dans une business function en C, le moteur de base de données maintient un verrou au niveau de la ligne dès le moment de la lecture jusqu'à ce que la transaction soit validée ou annulée, forçant les threads concurrents à faire la queue proprement.

Définition de la table personnalisée et de la structure de données
Les problèmes d'intégrité de base de données dans les environnements d'entreprise proviennent souvent de clés primaires mal typées dans les tables personnalisées. Pour notre schéma de table personnalisée F550101, nous définissons la clé primaire à l'aide d'un Unique Key ID (UKID)Identifiant numérique unique généré par le système pour garantir l'unicité d'un enregistrement. de 15 chiffres aux côtés du Document Number (DOCO) et du Document Type (DCTO). Cette structure composite spécifique, associée à un champ de statut personnalisé nécessitant des mises à jour conditionnelles, exige une validation stricte pour éviter les collisions d'écriture simultanées lorsque plusieurs processeurs batch s'exécutent en même temps.
Le mappage de l'UKID vers un type de données standard MathNumericType de données spécifique à JDE utilisé pour stocker des valeurs numériques avec une grande précision. dans la structure de données de la business function évite les erreurs de troncaturePerte de données survenant lorsqu'une valeur est trop grande pour son contenant. silencieuses qui se produisent lorsque les développeurs mappent des clés primaires numériques vers des types entiers C standard. Dans la conception de tables JDE, faire correspondre directement le type de colonne de la base de données aux structures internes de l'API garantit que le moteur d'exécution de l' Enterprise ServerServeur central JDE qui gère la logique métier et les processus batch. traite les valeurs de manière identique sans perte de précision sur les noyaux Linux et Windows.
Pour coordonner les écritures sécurisées, la structure de données de la business function doit explicitement renvoyer le pointeurVariable contenant l'adresse mémoire d'une autre variable. de limite de transaction et un indicateur de succès ou d'échec à l'application interactive ou à l'UBE appelant. Si un conflit de verrouillage d'enregistrement se produit pendant l'étape fetch-for-update, la business function assigne un indicateur de code de retour spécifique pour communiquer l'échec du verrouillage ou l'erreur de validation. Cela permet à l'application interactive appelante de déclencher instantanément un rollbackOpération annulant toutes les modifications effectuées lors de la transaction en cours. de la base de données ou de présenter un message d'erreur clair à l'utilisateur au lieu de laisser la pile d'appels échouer silencieusement. Nous mappons généralement cet indicateur à un élément de données d'un caractère comme EV01 dans la structure de données pour garder l'interface légère et standard.
Le pattern sécurisé Read-Before-Update dans une BSFN en C
Une erreur courante dans les business functions C personnalisées est de supposer qu'une lecture standard sécurise un enregistrement pour modification. Dans les environnements à haute concurrence, comme un grand centre de distribution avec des centaines d'utilisateurs simultanés exécutant des confirmations de bons de préparation en parallèle, deux threads liront fréquemment le même enregistrement F554211 simultanément, entraînant des écritures incohérentes. Pour éviter cela, votre première étape consiste à ouvrir la table cible avec l'API JDB_OpenTable, en passant explicitement le handleIdentifiant opaque utilisé pour manipuler une ressource système ou un objet. de transaction actif de la structure lpBhvrcom pour permettre les capacités de rollback.
Une fois le handle de table actif, vous devez immédiatement appeler l'API JDB_SetBehavior avec l'option JDB_BEHAVIOR_LOCK. Cet appel d'API spécifique instruit le moteur de base de données — qu'il s'agisse d'Oracle 19c ou de Microsoft SQL Server 2019 — d'émettre un équivalent de SELECT FOR UPDATE au niveau de la couche base de données. Sans cet indicateur de comportement explicitement défini, une lecture standard ne place pas de verrou exclusif sur la ligne, laissant l'enregistrement vulnérable aux lectures incohérentes par des applications interactives ou des UBEs batch concurrents.
Une fois le comportement de verrouillage établi, exécutez JDB_FetchKeyed pour récupérer l'enregistrement spécifique et vérifier son état actuel avant d'appliquer toute logique métier personnalisée. Dans une application réelle de registre d'inventaire personnalisé, cette étape garantit que la quantité en stock n'a pas changé entre l'affichage initial de la grille de recherche et l'événement de mise à jour réel de la base de données. S'appuyer sur les valeurs de l'écran au lieu de cette lecture fraîche et verrouillée est la façon dont des écarts d'inventaire de 5 % à 10 % s'insinuent dans le système.
Si l'enregistrement cible est déjà verrouillé par un autre thread de base de données, le moteur de base de données rejettera la requête. Au lieu de laisser le noyau CallObject échouer ou expirer — ce qui peut faire planter la session HTML de l'utilisateur sur le Tools Release 9.2.8 — vous devez gérer l'erreur JDB_ERR_RECORD_LOCKED avec élégance dans votre code C. Capturez ce code de retour, appelez jdeSetGBLError pour pousser un message convivial dans la file d'attente d'erreurs standard de JDE, et quittez la fonction proprement pour maintenir la stabilité du système.

Implémentation des limites de transaction et des rollbacks
Un désastre courant dans les environnements à haut volume, comme le traitement de 10 000 à 15 000 lignes de commande client par heure via EDIÉchange de Données Informatisé, standard pour le transfert de documents commerciaux entre entreprises., est l'apparition de verrous de base de données orphelins. Pour éviter cela, la BSFN C personnalisée doit explicitement lier ses opérations de base de données à la limite de transaction active de l'appelant. Ceci est réalisé en passant le handle de transaction d'environnement de la structure lpBhvrCom aux APIs JDB_OpenTableUser ou JDB_StartTransaction, garantissant que les opérations sur la table personnalisée participent à la transaction parente.
Si une validation de règle métier échoue après la lecture de l'enregistrement — comme la découverte d'un code de statut 560 inattendu au lieu de 520 — vous devez immédiatement déclencher un rollback. L'appel à JDB_RollbackTransaction en utilisant le handle de transaction actif garantit que toutes les insertions ou mises à jour antérieures non validées dans cette limite spécifique sont instantanément annulées au niveau de la base de données. Ne pas exécuter cette API laisse la base de données dans un état incohérent, où des enregistrements parents orphelins existent sans leurs détails enfants correspondants.
Une fois que la validation passe et que l'opération JDB_UpdateKeyed renvoie un statut JDEDB_PASSED réussi, vous devez rapidement valider la transaction. L'exécution de JDB_CommitTransaction écrit les modifications de manière permanente dans la base de données et, surtout, libère le verrou exclusif sur la ligne de base de données. Dans les environnements à haute concurrence, retarder cette validation de seulement 200 à 300 millisecondes peut provoquer une escalade de verrous SQL Server ou Oracle Database, bloquant les UBEs et les applications interactives concurrentes.
Une erreur critique lors de la gestion des erreurs est de contourner les routines de nettoyage lors d'une sortie prématurée de la fonction. Si vous quittez le code C lors d'un échec de validation sans appeler JDB_CloseTable, le middleware JDE maintient le handle de table actif en mémoire. Cette omission provoque une fuite de mémoireConsommation progressive de la mémoire vive causée par des ressources non libérées. silencieuse dans le noyau CallObject, consommant généralement 15 à 30 Ko par handle fuyant, et maintient les verrous de base de données ouverts indéfiniment jusqu'à ce que le processus du noyau soit recyclé.
Exemple de code : Détails d'implémentation de la BSFN C
Dans nos audits de business functions C personnalisées, nous trouvons fréquemment une instabilité du noyau CallObject causée par une initialisation paresseuse des pointeurs. Pour éviter la corruption de la mémoire au sein du runtime JDE, vous devez explicitement initialiser les variables locales, y compris le handle utilisateur HUSER et le handle de requête de table HREQUEST, en utilisant des APIs standard comme memset. Si vous laissez ces pointeurs non initialisés, un noyau CallObject multi-threadé s'exécutant sur votre serveur d'entreprise finira par référencer des adresses mémoire obsolètes, entraînant des plantages intermittents difficiles à isoler dans Server ManagerOutil d'administration JDE pour gérer et surveiller les serveurs et les instances..
Une fois votre handle utilisateur établi, l'ouverture de la table personnalisée cible nécessite une étape de validation que les développeurs ignorent souvent. Vous devez explicitement vérifier la valeur de retour de JDB_OpenTable par rapport à JDEDB_PASSED. Un échec ici indique une mauvaise configuration du mappage Object Configuration Manager (OCM)Composant JDE définissant la localisation des objets et des données. ou un problème de connexion à la base de données sous-jacente. Détecter cela tôt évite les opérations ultérieures sur un handle de requête nul, ce qui déclenche une violation d'accès fatale dans le noyau.
Lors de l'exécution de la mise à jour réelle, le code doit utiliser l'API JDB_UpdateKeyed plutôt que des fonctions de mise à jour génériques. Cette API nécessite que vous remplissiez et passiez la structure de clé exacte de la table personnalisée, garantissant que le moteur de base de données ne cible que la ligne spécifique correspondant à votre clé unique. En définissant explicitement la structure de l'index, vous empêchez la base de données de passer à un scan complet de la table, ce qui est une cause fréquente d'escalade de verrous lors de traitements à haut volume.
Enfin, votre fonction doit router tous les chemins logiques via un bloc de nettoyage dédié à la fin du code. Cette routine de sortie doit appeler JDB_CloseTable et JDB_FreeUser pour libérer les ressources allouées. Ne pas libérer ces handles provoque une fragmentation cumulative de la mémoire dans le noyau CallObject, forçant finalement un recyclage du noyau pendant les heures de pointe opérationnelles.
Test et validation des performances de verrouillage
Pour prouver que votre business function C personnalisée gère la concurrence sans deadlocks, lancez deux exécutions d'UBE locales parallèles ciblant la même plage d'enregistrements. Ouvrez les fichiers JDEDEBUG.log résultants et recherchez spécifiquement l'instruction SQL contenant SELECT ... FOR UPDATE (ou l'équivalent WITH (UPDLOCK) si vous travaillez sur Microsoft SQL Server). Si vous ne voyez pas cette syntaxe exacte précédant immédiatement votre instruction de mise à jour, votre Table I/O contourne le mécanisme de verrouillage natif du moteur de base de données, laissant votre table personnalisée vulnérable aux lectures incohérentes.
Pendant les heures de pointe, lorsque les volumes de transactions dépassent 50 000 à 100 000 écritures par heure, surveillez l'escalade des verrous de base de données à l'aide de la vue V$LOCK d'Oracle ou des Dynamic Management Views (DMVs) de SQL Server. Vous devez vérifier que les verrous au niveau de la ligne ne s'escaladent pas en verrous au niveau de la table, ce qui interrompt les sessions utilisateur dans les applications standard comme P4210 ou P4312. Si une escalade se produit, c'est généralement parce que la limite de transaction est maintenue ouverte trop longtemps par un appel JDB_CommitTransaction mal placé.
Pour minimiser la durée de ces verrous de base de données, mappez la BSFN personnalisée dans l'Object Configuration Manager pour qu'elle s'exécute exclusivement sur le serveur d'entreprise. L'exécution de la logique métier localement sur un serveur HTML ou un poste de travail introduit des sauts réseau qui prolongent les temps de rétention des verrous. Un cycle de lecture-mise à jour sécurisé typique à l'intérieur d'un environnement de serveur d'entreprise bien réglé devrait s'exécuter en moins de 20 millisecondes, contre plus de 100 millisecondes lorsqu'il est exécuté via un WANWide Area Network, réseau informatique couvrant une grande zone géographique. ou un sous-réseau mal routé. Maintenez cette latence réseau faible pour éviter que la contention de verrouillage ne dégrade les performances des applications interactives concurrentes.
L'implémentation de ces patterns de Table IO sécurisés est essentielle lors de la gestion d'un parc de code personnalisé de 5 000 à 15 000 objets. S'assurer que votre équipe de développement applique systématiquement ces limites transactionnelles est ce qui sépare les déploiements d'entreprise stables de ceux en proie à des verrous de base de données intermittents et des défaillances de noyau. Pour un examen plus approfondi de l'optimisation de vos business functions personnalisées basées sur le C, contactez notre équipe d'architecture d'entreprise pour planifier un audit de code.