2017-11-09 5 views
1

Ich möchte Hibernate verwenden, um einen eindeutigen Primärschlüssel für eine Entität zu generieren, die zufällig ist - z. B. für Zahlungsbestätigungsnummern, Hotelbuchungsnummern, Geschenkkartencodes usw. - jederzeit, wenn ein Kunde mit einem eindeutigen Wert konfrontiert wird, um eine Entität zu identifizieren.Generieren Sie eindeutige, zufällige alphanumerische Primärschlüssel der Länge 10

Sie sollten von Endbenutzern nicht vorhersehbar sein, müssen aber nicht kryptographisch sicher sein. Die Länge muss 10 Zeichen alphanumerisch sein, wobei alle Großbuchstaben zu verwenden sind.

Es gibt viele ähnliche Fragen, aber keine scheint das Problem zu lösen. Ich kann nicht der Erste sein, der dieses Problem hat.

Ich möchte die Brute-Force-Methode zu vermeiden, nur eine zufällige alphanumerische Zeichenfolge generieren und überprüfen, ob es in der Datenbank vorhanden ist oder nicht.

+0

Wenn es zufällig ist, dann ist es definitionsgemäß nicht eindeutig. Gibt es einen Grund, warum Sie eine bestimmte Formatanforderung haben und daher keine GUID verwenden können? – azurefrog

+0

Weil es etwas ist, das der Benutzer zum Beispiel verwenden muss, um in ein Feld einzugeben, und die Länge wäre dann unerschwinglich. Ich brauche nicht unbedingt * zufällig *, nur nicht vorhersehbar (oder zumindest nicht leicht vorhersagbar. Mit anderen Worten, ich möchte keine sequentiellen Ganzzahlen in unserer Datenbank für Bestellnummern) – Airhead

Antwort

1

Sie können 10-stellige Basis-36-Nummern generieren. Um sie unberechenbar zu machen, anstatt sie einzeln zu durchlaufen, können Sie zwischen ihnen mit jedem Wert springen, der relativ prim zu 36^10 ist.

Zum Beispiel:

public class Unique { 
    private static final long SKIP = 1656158440062971L; 
    private static final long MOD = 3656158440062976L; 
    private static final long BASE = 36L; 

    public static class ExhaustedException extends RuntimeException { 
     public ExhaustedException() { super("No more codes"); } 
    } 

    private long currentValue = 0L; 

    public static void main(String[] args) { 
     int max = Integer.parseInt(args[0]); 
     Unique generator = new Unique(); 
     for (int i = 0; i < max; i++) { 
      System.out.println(generator.nextCode()); 
     } 
    } 

    public synchronized String nextCode() { 
     currentValue = (currentValue + SKIP) % MOD; 
     if (currentValue == 0L) { 
      throw new ExhaustedException(); 
     } 
     return codeFromLong(currentValue); 
    } 

    private String codeFromLong(long value) { 
     StringBuilder code = new StringBuilder(); 
     for (int i = 0; i < 10; i++) { 
      int digit = (int) (value % BASE); 
      code.insert(0, charFromDigit(digit)); 
      value /= BASE; 
     } 
     return code.toString(); 
    } 

    private char charFromDigit(int digit) { 
     if (digit < 10) return (char) ('0' + digit); 
     return (char) ('A' + (digit - 10)); 
    } 
} 

Dies wird 10-stellige alphanumerischen Codes in einer scheinbar zufälligen Reihenfolge erzeugen. Es wird nach 3.656.158.440.062.976 (3,6 Billiarden) Codes wiederholen. Um Duplikate zu vermeiden, wird vor dem Generieren einer 0 und anschließendem Wiederholen ein ExhaustedException ausgelöst. Es ist garantiert, jeden Code einmal und nur einmal zu besuchen, da 1.656.158.440.062.971 relativ prim der gesamten Zykluslänge ist.

Ich habe diesen Wert generiert, indem ich die erste Ziffer in eine 1 ändere und die letzte Ziffer anpasse. Es ist nicht wichtig, was genau diese Zahl ist, und sie muss keine Primzahl sein, aber sie darf keine gemeinsamen Faktoren mit 36 ​​^ 10 teilen (muss relativ prim sein), und sie sollte groß sein, aber nicht nahe bei 36^10, so dass sich die meisten oder alle Ziffern bei jedem Drehen der Kurbel ändern.

Dies ist ein in sich geschlossenes Programm, aber Sie werden wahrscheinlich den aktuellen Wert in die Datenbank setzen und diesen Code möglicherweise sogar hinter eine gespeicherte Prozedur stellen. In diesem Fall möchten Sie vielleicht einen bestimmten Sentinel-Wert zurückgeben angezeigt, dass die Sequenz erschöpft ist. Ich habe die Methode gemacht, die den nächsten Code generiert synchronized; Sie müssen auf die eine oder andere Weise sicherstellen, dass keine zwei Anrufer denselben Code erhalten.

Hinweis: Dies kann zu einem Engpass in Ihrer App werden.

Ich würde auch einen Wrapper um ihn legen und nach einer Stoppliste von Kraftausdrücken suchen. Sie möchten einem Kunden keinen Code mit einem vierstelligen oder anderen anstößigen Wort geben. Wenn ein Code ein schlechtes Wort als Teilstring enthält, wirf ihn einfach weg und erzeuge den nächsten Code.

Verwandte Themen