Вероятность коллизии при использовании наиболее значимых битов UUID в Java

StackOverflow https://stackoverflow.com/questions/325443

  •  11-07-2019
  •  | 
  •  

Вопрос

Если я использую Long uuid = UUID.randomUUID (). getMostSignificantBits () какова вероятность возникновения коллизии. Он обрезает наименее значимые биты, поэтому есть вероятность, что вы столкнетесь с коллизией, верно?

Это было полезно?

Решение

Согласно документации , Статический метод UUID.randomUUID () генерирует UUID типа 4.

Это означает, что шесть битов используются для некоторой информации о типе, а оставшиеся 122 бита назначаются случайным образом.

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

Я бы сказал, что вы в безопасности. Обратите внимание, однако, что это совершенно не так для других типов UUID, как упоминает Карл Селеборг.

Кстати, вам было бы немного лучше, если бы использовали наименее значимую половину UUID (или просто сгенерировали случайный длинный, используя SecureRandom).

Другие советы

У Раймонда Чена действительно отличная запись в блоге об этом:

GUID глобально уникальны, но подстроки GUID не являются

Я думаю, что это лучший пример для использования randomUUID:

http://www.javapractices.com/topic/TopicAction.do? Id = 56

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

Существуют разные уровни уникальности.

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

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

Используйте время ГГГГДДДД (год + день года) в качестве префикса. Это уменьшает фрагментацию базы данных в таблицах и индексах. Этот метод возвращает byte [40] . Я использовал его в гибридной среде, где SID Active Directory ( 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();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top