Si vous choisissez de maintenir votre conception actuelle de mise à jour de la colonne sequenceTable.id
chaque fois que vous souhaitez générer un nouveau numéro de séquence, vous devez vous assurer:
- le processus « courant » obtient un verrou exclusif sur la ligne contenant le numéro de séquence désirée
- le processus « courant » met alors à jour la ligne désirée et extrait la valeur nouvellement mis à jour
- le processus « courant » libère le verrou exclusif
Bien que ce qui précède peut être mis en œuvre au moyen d'un begin tran
+ update
+ select
+ commit tran
, il est en fait un peu plus facile avec une seule instruction update
, par exemple:
create procedure mySequence
AS
begin
declare @seqNum int
update sequenceTable
set @seqNum = id + 1,
id = id + 1
select @seqNum
end
La déclaration update
est sa propre transaction si la mise à jour La colonne id
et l'affectation @seqNum = id + 1
sont exécutées sous un verrou exclusif dans la transaction update
. Gardez à l'esprit que le verrou exclusif empêchera les autres processus d'obtenir une nouvelle valeur d'ID; Le résultat net est que la génération de nouvelles valeurs d'identifiant sera monothread/séquentielle
Bien que cela soit 'bon' dans la perspective de s'assurer que tous les processus obtiennent une valeur unique, cela signifie que cette instruction particulière devient un goulot d'étranglement si vous avez plusieurs processus qui touchent le update
simultanément.
Dans une telle situation (volume élevé de update
s), vous pouvez alléger certains conflits en appelant le proc stocké moins souvent; ceci pourrait être accompli en demandant aux processus appelant une plage de nouvelles valeurs id (par exemple, passer @increment
comme paramètre d'entrée à la proc, alors au lieu de id + 1
vous utilisez id + @increment
), le processus appelant sachant alors qu'il peut utiliser des numéros de séquence (@[email protected]+1
) à @seqNum
.
Évidemment (?) tout processus qui utilise un proc stocké pour générer des valeurs 'next id' ne fonctionne que si * ALL * processus a) appelle toujours le proc pour une nouvelle valeur d'identifiant et b) * TOUS * les processus utilisent uniquement la valeur d'identifiant retournée par le proc (par exemple, ils ne génèrent pas leurs propres valeurs d'id).
S'il existe une possibilité d'applications ne suivant pas ce processus (appelez proc pour obtenir une nouvelle valeur d'ID), vous pouvez envisager de pousser la création des valeurs d'ID uniques vers la table où ces valeurs sont insérées; en d'autres termes, modifiez la colonne id de la table cible pour inclure l'attribut identity
; ceci élimine le besoin pour les applications d'appeler le proc stocké (pour générer un nouvel identifiant) et assure (toujours) qu'un identifiant unique est généré pour chaque insert.
Je ne pense pas qu'il y ait de synchronisation dans votre procédure - cela signifie que vos premières instructions 'select' et' update' ont une course - il est possible de sélectionner simultanément un autre processus pour toucher votre table entre select et update d'un autre processus, vous donnant ainsi deux des mêmes valeurs. (Votre question n'est pas liée à Java, d'ailleurs). –
D'accord avec @ M.Prokhorov - ce n'est pas strictement une question Java. Même ainsi, pourquoi ne pas simplement utiliser une séquence réelle? Les applications Java multithread les utilisent depuis des années –
Parce que db ne fournit pas de séquence sybase et que cette procédure stockée sera appelée par plusieurs JVM et threads. Aussi la mise à jour ne fonctionnera que quand la condition rencontrera la même version que je le ferais sinon elle ajoutera une nouvelle valeur, je l'ai testée avec 500 appels du test d'unité Java et chaque fois cela donne des résultats différents. Je demande à confirmer peut-être quelques choses hits. – user460293