8
votes

Comment générer un numéro de commande unique?

Je cherche un bon moyen de générer un identifiant de commande unique. Pouvez-vous voir des problèmes avec le code ci-dessous? XXX

Je vais vérifier que le numéro est unique dans la base de données avant de créer la commande.


3 commentaires

Purement théoriquement, les hachages peuvent entrer en collision.


Ce n'est sûrement pas vraiment unique que vous recherchez, juste le prochain numéro séquentiel ... Je suis d'accord avec le folk ci-dessous en parlant de l'utilisation d'une colonne d'identité.


@Developer Art: Rien de théorique à ce sujet. Hashes collide tout le temps . Il n'y a que quatre milliards d'entre eux, bien sûr, ils vont bien sûr entrer en collision.


7 Réponses :


7
votes

Qu'en est-il d'avoir un champ d'identité dans la base de données le faire pour vous?

Il aura également l'avantage que les numéros de commande supprimés / annulés ne soient pas réutilisés (ce qui est bon ou peut être nécessaire pour la comptabilité).


0 commentaires

0
votes

Si vous utilisez SQL Server, vous devez vraiment rechercher la spécification d'identité. Cela vous permet de faire cela avec facilité et vitesse.

Votre solution n'est pas unique car les choses peuvent se produire si rapidement dans le système que deux processus, fonctionnant dans une séquence ou simultanément, peuvent obtenir la même valeur de tick.


1 commentaires

L'ID client variera pour chaque commande. Je pense que la combinaison d'une pièce d'identité client avec des tiques devrait produire la valeur unique que je après.



25
votes

Si vous stockez vos enregistrements dans une base de données, vous devez vraiment examiner les capacités disponibles pour générer des clés de substitution uniques. dans SQLServer Ce serait un identité champ et en oracle, ce serait un champ qui utilise un séquence pour générer une nouvelle valeur.

S'il y a une raison impérieuse pour laquelle vous ne pouvez pas utiliser Votre base de données pour générer une clé unique, vous devez consulter quelque chose comme un GUID - qui a une probabilité plus forte plus élevée que la manipulation de date-heure de générer une valeur unique. Les GUID peuvent être trivialement convertis en chaînes. Votre identifiant serait donc une chaîne dans ce cas.

Ce que vous faites avec des hachages n'est pas une bonne idée - Rien de Gaurantes qui hachait Soyez unique - et dans de nombreux cas, ils font effectivement entrer en collision. GUIDS - Ne fournissez pas une garantie de 100% de l'unicité à travers les machines mais sur une seule machine, elles devraient toujours être uniques. Et même sur des machines, leurs chances de collision sont extrêmement éloignées. En outre, en utilisant le temps de la machine comme moyen de construire la valeur sous-jacente est soumis à des conditions de raquette (comme ces ERIC décrit).

Les GUID sont des valeurs de 128 bits, de sorte que vous ne pouvez pas les représenter. comme un simple int ou long . Il vous faudrait que vous utilisiez une chaîne comme IDS , qui peut ou non être possible dans votre cas, en fonction des autres considérations (comme si vous contrôlez ou non le modèle de données). Si vous pouvez les utiliser, l'utilisation d'un GUID est vraiment simple: xxx

Si vous devez utiliser vraiment un identifiant numérique et que vous êtes prêt à abandonner facilement votre application à travers Plusieurs serveurs, vous pouvez utiliser un numéro global incrémentant automatique pour fournir une clé unique. Vous devrez semer ce numéro avec la valeur disponible suivante (max + 1) de votre base de données lorsque l'application démarre. Vous devrez également protéger cette valeur de l'utilisation simultanée de plusieurs threads. J'enverrais cette responsabilité dans une classe: xxx

edit: en ce jour et L'âge, des raisons impérieuses de générer des identifiants uniques dans votre couche d'application plutôt que dans la base de données sont très rares. Vous devriez vraiment utiliser les capacités que la base de données fournit.


0 commentaires

0
votes

J'utiliserais la colonne d'identité et, sinon, utilisez System.Guid.NewGuid () pour générer un GUID pour vous.


0 commentaires

15
votes

Supposons que vous ayez deux identifiants clients qui diffèrent de 100, et ils arrivent à la fois de faire une commande de 100 unités de temps. Votre unicité vient de sortir la fenêtre.

Vous dites que vous allez vérifier la base de données pour l'unicité; Vous ne dites pas ce que vous allez faire s'il y a une collision. Vous ne dites pas non plus ce que vous allez faire sur les conditions de course; Supposons que deux identifiants de commande collisionnaires soient créés en même temps, ni dans la base de données. Vous demandez à la base de données sur deux threads différents si l'élément est unique; il est. Vous entrez ensuite les deux et l'unicité a été violée même si le chèque a été fait.

C'est un moyen vraiment vraiment mauvais d'obtenir un caractère unicité. Ce qui serait mieux consiste à déplacer cela dans la couche de base de données. Vous pouvez maintenir un compteur mondial et threadsafe des commandes et attribuer chaque nouvel ordre le prochain numéro de commande.

Incidemment, pendant de nombreuses années, j'ai posé une variation sur cette question en tant que question d'entretien technique. J'ai remarqué une forte corrélation entre l'ensemble de personnes qui tentent d'utiliser du temps comme une source d'unicité et l'ensemble de personnes qui ne sont pas embauchées. Le temps est un source terrible de l'unicité; Beaucoup de choses différentes peuvent arriver en même temps.

Qu'est-ce qui est encore pire utilise des nombres aléatoires. Les nombres aléatoires sont une source d'unicité encore pire que les horodatages. Supposons que vous ayez un générateur de nombres vraiment aléatoires générant des entiers aléatoires 32 bits pour les identifiants de commande. Combien de commandes avez-vous besoin d'avoir avant que les chances soient meilleures que ce que vous avez généré deux commandes avec le même identifiant? La réponse surprend beaucoup de personnes: il n'ya que 77 000 avant environ 50% de chances que vous avez généré deux commandes avec le même numéro (et seulement 9300 jusqu'à ce qu'il y ait une chance de 1%.)

N'oubliez pas: ce que vous êtes après est une garantie de l'unicité. Pas un unicité probable , mais une garantie de fer à repasser qu'un numéro d'ordre fait référence à une ordonnance exacte. Si c'est ce dont vous avez besoin, assurez-vous de mettre en œuvre cela.


0 commentaires

0
votes

2 commentaires

Si vous suggérez que l'ID de commande soit généré au hasard en utilisant le véritable aléatoire, il s'agit d'une idée dangereuse . Les chances d'obtenir une collision entre deux nombres vraiment aléatoires de 32 bits augmentent à> 50% après seulement 77 000 tentatives!


@ERIC: Vous êtes correct, je ne suggère pas d'identifiant de commande # être généré aléatoirement, mais qui générant un certain nombre doit être informé des pièges de telles opérations, comme vous l'avez souligné. La théorie du nombre aléatoire est un bon endroit pour trouver de tels pièges afin qu'ils puissent être évités.



0
votes

Vous pouvez utiliser une table séparée appelée commande. La table ressemblerait à ceci:

[commandercounter] Identifiant CourantCount - Long

La table ne contiendra qu'une seule rangée. ID: 1, CourantCount = 1.

Lorsque vous souhaitez générer un nouveau numéro de commande, vous accédez à la table à l'aide d'un service, CommandeNumberGenerserVice qui verrouille l'accès à la table, obtenez le numéro actuel, l'incrémentez-la par combien vous voulez. Après incrément, stockez la valeur actuelle dans la table.

Donc, par exemple, si vous voulez aller 1 par 1. Var Ordnum = _OrdernumbergenerserVice.GeneratenextOrderNum (); ordnum sera 2


0 commentaires