18-значный уникальный идентификатор - надежность кода
Я хочу, чтобы число было уникальным навсегда, я придумал следующий код, он генерирует число и добавляет в его конец контрольную цифру, я хотел бы знать, насколько надежен этот код?
public void GenerateUniqueNumber(out string ValidUniqueNumber) {
string GeneratedUniqueNumber = "";
// Default implementation of UNIX time of the current UTC time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
string FormatedDateTime = Convert.ToInt64(ts.TotalSeconds).ToString();
string ssUniqueId = DateTime.UtcNow.ToString("fffffff");
//Add Padding to UniqueId
string FormatedUniqueId = ssUniqueId.PadLeft(7, '0');
if (FormatedDateTime.Length == 10 && FormatedUniqueId.Length == 7)
{
// Calculate checksum number using Luhn's algorithm.
int sum = 0;
bool odd = true;
string InputData = FormatedDateTime + FormatedUniqueId;
int CheckSumNumber;
for (int i = InputData.Length - 1; i >= 0; i--)
{
if (odd == true)
{
int tSum = Convert.ToInt32(InputData[i].ToString()) * 2;
if (tSum >= 10)
{
string tData = tSum.ToString();
tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
}
sum += tSum;
}
else
sum += Convert.ToInt32(InputData[i].ToString());
odd = !odd;
}
//CheckSumNumber = (((sum / 10) + 1) * 10) - sum;
CheckSumNumber = (((sum + 9) / 10) * 10) - sum;
// Compute Full length 18 digit UniqueNumber
GeneratedUniqueNumber = FormatedDateTime + FormatedUniqueId + Convert.ToString(CheckSumNumber);
}
else
{
// Error
GeneratedUniqueNumber = Convert.ToString(-1);
}
ValidUniqueNumber = GeneratedUniqueNumber;
}
РЕДАКТИРОВАТЬ: разъяснение GUID не может быть использован, номер необходимо будет ввести в систему IVR через телефонную клавиатуру.
9 ответов
Вы не можете использовать GUID, но вы можете создать свой собственный формат уникального номера, похожий на GUID, который основан на MAC-адресе аппарата (пробел) и текущем времени и дате (время). Это гарантированно будет уникальным, если все машины имеют синхронизированные часы.
Для получения дополнительной информации, пожалуйста, смотрите здесь
Есть несколько проблем с этим методом:
Вы просто подсчитываете количество миллисекунд с 1 января 1970 года. Вы можете получить это от
ts.TotalSeconds
округляется до 0,0000001. Все ваши преобразования и миллисекундные вычисления не нужны.10 лет - это примерно 3×10¹¹ миллисекунд. Вы сохраняете 17 значащих цифр, поэтому в течение следующих 10 лет первые 5 цифр никогда не изменятся и не могут использоваться для различения цифр. Они бесполезны.
Вы генерируете числа за миллисекунды между 1970 и сейчас? Если нет, их также нельзя использовать для различения чисел, и они бесполезны.
Это полностью зависит от того, какая машина возвращает дату. Любой, кто имеет доступ к этой машине, может генерировать любые "уникальные" числа, которые они хотят. Это проблема?
Любой, кто видит одно из этих чисел, может сказать, когда он был сгенерирован. Это проблема?
Любой может предсказать, какое число будет сгенерировано. Это проблема?
1015 миллисекунд - это около 30000 лет. После этого ваш алгоритм будет повторять числа. Похоже, давно, но вы указали "навсегда" и 30000 лет не "навсегда". Вы действительно имеете в виду "навсегда"?
Если я правильно понимаю вашу реализацию, она использует только текущую дату / время в качестве основы. Это означает, что если вы создадите два идентификатора одновременно, они не будут уникальными.
Использование системного времени является хорошим началом, но оно дает вам коллизии, если вам нужно генерировать два UID одновременно. Это не помогает, если вы используете формат "fffffff": разрешение часов Windows составляет всего 15-16 мс, поэтому только один или два из этих "f" приносят пользу.
Кроме того, ваш подход говорит вам точно, когда был создан идентификатор. В зависимости от ваших потребностей это может быть желательной функцией или угрозой безопасности.
Вам понадобятся ваши идентификаторы для включения другой информации вместо или в дополнение к времени. Некоторые возможные варианты:
- Случайное число
- Циклический счетчик
- Хеш имени программы (если вам нужны эти идентификаторы в нескольких программах)
- MAC-адрес или другой идентификатор для машины (если идентификаторы должны быть уникальными для нескольких компьютеров)
Если вы хотите обеспечить уникальность, сохраните свои идентификаторы в базе данных, чтобы вы могли проверять наличие дубликатов.
Вы не говорите, для чего используются цифры. Есть ли у них какая-то ценность, связанная с ними? Будет ли проблемой, если пользователи смогут выяснить схему и угадать действительные номера билетов?
Если для этих чисел важно угадать, эта схема рушится; что-то, что выводит данные, которые выглядят действительно случайными, было бы лучше. Вы можете взять монотонно увеличивающийся серийный номер и зашифровать его с помощью блочного шифра (с размером блока 64 бита); это дает вам 64-битный вывод или около 20 десятичных цифр, которые вы можете взять (скажем) последние 18 из. (Если важна обратимость, т. Е. С учетом номера билета, который вы хотите иметь возможность восстановить серийный номер, вам следует быть здесь более осторожным.)
Вам нужна чугунная 100% гарантия того, что номера билетов никогда не будут прежними? Если это так, вам нужно сохранить их в базе данных и пометить их при использовании. Если вы сделаете это, может быть разумно просто использовать хороший генератор случайных чисел и каждый раз проверять наличие дубликатов.
Поскольку вы упомянули (в комментариях), что идентификаторы хранятся в БД, вы можете сгенерировать идентификаторы, используя метод, который вы упомянули, или случайным образом и проверить наличие в БД.
Если он уже существует, создайте новый, иначе все готово.
Однако я хотел бы убедиться, что проверка на наличие идентификатора и фактическое сохранение записи в БД выполняются в транзакции, в противном случае вы рискуете сделать еще один запрос на создание этой записи между проверкой Идентификатор и создание строки.
Также просто проверяю, почему не работает автоприращение числа, сгенерированного самой базой данных? БД гарантирует ее уникальность (для этой таблицы в любом случае)
Как говорит "Эндрю Хэйр", вы можете использовать Guid. О вашем коде ответ "НЕТ"! потому что, если DateTime компьютера клиента был неправильным или результат изменения может быть пара или больше!
Во всяком случае, нет такой вещи, как случайность Вот предложение.
- Создайте свой собственный "случайный" 18-значный номер
- Перед отправкой пользователю, проверьте его на существующие в БД
- Если уже в БД, промыть и повторить.