Создание уникального идентификатора фиксированной длины - PullRequest
4 голосов
/ 11 ноября 2011

Что ж, я искал способы генерирования UID в java-коде (большинство из них также приходят в stackoverflow). Лучше всего использовать UUID java для создания уникальных идентификаторов, так как он использует метку времени. Но моя проблема в том, что он длиной 128 бит и мне нужна более короткая строка, например, 14 или 15 символов. Итак, я разработал следующий код для этого.

Date date = new Date();
Long luid = (Long) date.getTime();
String suid = luid.toString();
System.out.println(suid+": "+suid.length() + " characters");

Random rn = new Random();
Integer long1 = rn.nextInt(9);
Integer long2 = rn.nextInt(13);

String newstr = suid.substring(0, long2) + " " + long1 + " " + suid.subtring(long2);
System.out.println("New string in spaced format: "+newstr);
System.out.println("New string in proper format: "+newstr.replaceAll(" ", ""));

Обратите внимание, что я просто отображаю строку, отформатированную и правильно отформатированную для сравнения только с исходной строкой.

Будет ли это гарантировать 100% уникальный идентификатор каждый раз? Или вы видите какую-либо возможность повторения чисел? Кроме того, вместо вставки случайного числа в случайную позицию, которая «может» создать повторяющиеся числа, я мог бы сделать это либо в начале, либо в конце. Это для завершения необходимой длины моего UID. Хотя это может не сработать, если вам нужен UID длиной менее 13 символов.

Есть мысли?

Ответы [ 2 ]

3 голосов
/ 16 ноября 2011

Это не сработает, если это, конечно, распределенная система, но как насчет чего-то вроде следующего:

private AtomicLong uniqueId = new AtomicLong(0);
...
// get a unique current-time-millis value 
long now;
long prev;
do {
    prev = uniqueId.get();
    now = System.currentTimeMillis();
    // make sure now is moving ahead and unique
    if (now <= prev) {
        now = prev + 1;
    }
    // loop if someone else has updated the id
} while (!uniqueId.compareAndSet(prev, now));

// shuffle it
long result = shuffleBits(now);
System.out.println("Result is " + Long.toHexString(result));

public static long shuffleBits(long val) {
    long result = 0;
    result |= (val & 0xFF00000000000000L) >> 56;
    result |= (val & 0x00FF000000000000L) >> 40;
    result |= (val & 0x0000FF0000000000L) >> 24;
    result |= (val & 0x000000FF00000000L) >> 8;
    result |= (val & 0x00000000FF000000L) << 8;
    result |= (val & 0x0000000000FF0000L) << 24;
    result |= (val & 0x000000000000FF00L) << 40;
    result |= (val & 0x00000000000000FFL) << 56;
    return result;
}

Перестановка битов может быть улучшена, чтобы генерировать больше изменений в значениях на каждой итерации.Вы упомянули, что не хотите, чтобы числа были последовательными, но не указали требование полной случайности.

Конечно, не так хорошо, как UUID, но быстрее, чем операция с базой данных.

1 голос
/ 13 ноября 2011

Самый простой способ - использовать последовательности базы данных, если они доступны.Если это не так, вы можете смоделировать их следующим образом:

  1. Создайте таблицу, в которой есть столбец, в котором будет храниться максимальное используемое значение (изначально 0).Некоторые приложения создают несколько строк, где каждая строка контролирует определенный уникальный идентификатор, но все, что вам действительно нужно, это одна строка.Для этого примера предположим, что структура таблицы выглядит следующим образом:

    ID_TABLE
    ID_NAME    VARCHAR(40); -- Or whatever type is appropriate
    ID_COLUMN  INTEGER; -- Or whatever type is appropriate
    
  2. Каждый процесс резервирует строки, выполняя следующие действия:

    a. Begin Txn;
    b. Update ID_TABLE set ID_VALUE = ID_VALUE + <n> where ID_NAME = <name>;     
    c. Select ID_VALUE from ID_TABLE where ID_NAME = <name>;  
    d. Commit Txn;
    

    Если все это успешно завершено, тогда вы только что зарезервировали диапазон (val - n + 1) через val, где val - возвращаемое значение из шага c.выше.

  3. Каждый процесс раздает идентификаторы из зарезервированного им диапазона.Если процесс многопоточный, он должен обеспечивать синхронизацию, чтобы каждое значение передавалось не более одного раза.Когда он исчерпывает запас своих значений, он возвращается к шагу 2 и резервирует больше значений.Обратите внимание, что не все зарезервированные значения гарантированно будут использоваться.Если процесс завершается без использования всех зарезервированных значений, неиспользуемые значения теряются и никогда не используются.

...