Ймовірність зіткнення з використанням найбільш значущих бітів UUID на Java


235

Якщо я використовую, Long uuid = UUID.randomUUID().getMostSignificantBits()наскільки ймовірно отримати зіткнення. Це відрізає найменш значущі шматочки, тому є ймовірність, що ви зіткнетесь зіткненням, правда?

Відповіді:


213

Згідно з документацією , статичний метод UUID.randomUUID()генерує UUID типу 4.

Це означає, що шість бітів використовуються для деякої інформації типу, а решта 122 біт призначаються випадковим чином.

Шість випадкових бітів розподіляються чотирма в найбільш значущій половині UUID і двома в найменш значній половині. Отже, найзначніша половина вашого UUID містить 60 біт випадковості, що означає, що вам потрібно в середньому генерувати 2 ^ 30 UUID, щоб отримати зіткнення (порівняно з 2 ^ 61 для повного UUID).

Тому я б сказав, що ви досить безпечні. Зауважте, однак, що це абсолютно не вірно для інших типів UUID, як зазначає Карл Селеборг.

До речі, вам було б трохи краще, використовуючи щонайменше значну половину UUID (або просто генеруючи випадковий довгий за допомогою SecureRandom).


3
Я не впевнений, що це цілком правильно - дивлячись на реалізацію, зрозуміло, що інформація про версію / варіант зберігається не в найбільш значущих бітах, а десь посередині.
Том

2
@RasmusFaber Коментар Тома правильний: Відповідь тут неправильна щодо шести найбільш значущих бітів, що є типовою інформацією. Дійсно є шість біт невипадкових даних, але чотири біти ідентифікують Версію 4, а два інші біти зарезервовані. Чотири і два біти розташовані в різних положеннях біля середини 128-бітного значення. Дивіться статтю у Вікіпедії .
Василь Бурк



10

Вам краще просто генерувати випадкове довге значення, тоді всі біти є випадковими. У Java 6 новий Random () використовує System.nanoTime () плюс лічильник як насіння.

Існують різні рівні унікальності.

Якщо вам потрібна унікальність на багатьох машинах, ви можете мати центральну таблицю бази даних для розподілу унікальних ідентифікаторів або навіть партій унікальних ідентифікаторів.

Якщо вам просто потрібно мати унікальність в одному додатку, ви можете просто мати лічильник (або лічильник, який починається з currentTimeMillis () * 1000 або nanoTime () залежно від ваших вимог)


7

Використовуйте YYYYDDDDяк префікс час (рік + день року). Це зменшує фрагментацію бази даних у таблицях та індексах. Цей метод повертається byte[40]. Я використовував його в гібридному середовищі, де Active Directory SID ( varbinary(85)) є ключем для користувачів LDAP, а ідентифікований автоматично створений програмою ідентифікатор використовується для користувачів, які не є LDAP. Також велика кількість транзакцій на день у транзакційних таблицях (банківська індустрія) не може використовувати стандартні Intтипи для ключів

private static final DecimalFormat timeFormat4 = new DecimalFormat("0000;0000");

public static byte[] getSidWithCalendar() {
    Calendar cal = Calendar.getInstance();
    String val = String.valueOf(cal.get(Calendar.YEAR));
    val += timeFormat4.format(cal.get(Calendar.DAY_OF_YEAR));
    val += UUID.randomUUID().toString().replaceAll("-", "");
    return val.getBytes();
}

3
Чому б замість цього не використовувати стандартний V1 UUID?
ShadowChaser
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.