2010-02-15 3 views
8

Я ищу хороший способ создания уникального идентификатора заказа. Вы видите какие-либо проблемы с кодом ниже?Как создать уникальный номер заказа?

int customerId = 10000000; 

long ticks = DateTime.UtcNow.Ticks; 

long orderId = customerId + ticks; 

int orderNumber = orderId.GetHashCode(); 

Я собираюсь проверить, что номер уникален в базе данных, прежде чем создавать заказ.

+2

Чисто теоретически, хэши могут столкнуться. – 2010-02-15 16:11:00

+0

Несомненно, это не уникально, что вы ищете, просто следующий порядковый номер ... Я согласен с тем, что люди говорят об использовании столбца идентификации. – Paddy

+3

@Developer Art: Ничего теоретического о нем. Хеши сталкиваются * все время *. Их доступно только около четырех миллиардов, поэтому, конечно, они столкнутся. –

ответ

7

А как насчет того, что поле IDENTITY в базе данных сделает это за вас?

Это также будет иметь то преимущество, что удаленные/отмененные номера заказов не будут использоваться повторно (что хорошо или даже может потребоваться для учета).

0

ЕСЛИ вы используете SQL Server, вам действительно нужно найти спецификацию IDENTITY. Это позволяет вам делать это с легкостью и скоростью.

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

+0

Идентификатор клиента будет отличаться для каждого заказа. Я думаю, что объединение идентификатора клиента с тиками должно дать уникальное значение, которое я получаю после. –

24

Если вы храните свои записи в базе данных, вы должны действительно изучить возможности, доступные там, чтобы генерировать уникальные суррогатные ключи. В SQLServer это будет поле IDENTITY, и в Oracle это будет поле, которое использует SEQUENCE для генерации нового значения.

Если есть веская причина, почему вы не можете использовать базу данных для генерации уникального ключа, вы должны смотреть на что-то вроде Guid - который имеет раздо большую вероятность, чем манипуляции даты и время для создания уникального значения , Гиды могут быть тривиально преобразованы в строки, поэтому ваш идентификатор будет строкой в ​​этом случае.

То, что вы делаете с хешами, не является хорошей идеей - ничто не гарантирует, что хеши будут уникальными - и во многих случаях они действительно сталкиваются. Гиды - не обеспечивают 100% гарантию уникальности через машины, но на одной машине они всегда должны быть уникальными. И даже на машинах их шансы на столкновение крайне удалены. Кроме того, использование машинного времени в качестве способа создания базового значения зависит от условий гонки (например, описывает Эрик).

Гиды - это 128-битные значения, поэтому вы не можете представлять их как простые int или long. Это потребует от вас использовать строку в качестве идентификаторов, что может быть или не быть возможно в вашем случае, в зависимости от других соображений (например, независимо от того, управляете ли вы моделью данных). Если использовать их, используя Guid очень просто:

string customerId = Guid.NewGuid().ToString(); // fetch new guid and save as string 
string orderNumber = Guid.NewGuid().ToString(); // same story here... 

Если вы действительно должны использовать числовой идентификатор, и вы готовы легко отказаться от масштабирования приложения на нескольких серверах, вы могли бы использовать автоинкрементный глобальный номер для предоставления уникального ключа. Вам нужно будет занести это число со следующего доступного значения (max + 1) из вашей базы данных при запуске приложения. Вы также должны были бы защитить это значение от одновременного использования из нескольких потоков.Я бы обернуть эту ответственность в классе:

class static UniqueIDGenerator 
{ 
    // reads Max+1 from DB on startup 
    private static long m_NextID = InitializeFromDatabase(); 

    public static long GetNextID() { return Interlocked.Increment(ref m_NextID); } 
} 


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

+4

+1 - Очень хороший ответ. – JasCav

0

Я бы использовал столбец IDENTITY, и если это не так, используйте System.Guid.NewGuid() для создания GUID для вас.

14

Предположим, что у вас есть два идентификатора клиента, которые отличаются на 100, и они, как правило, делают заказ на расстоянии 100 единиц времени. Твоя уникальность просто вышла из окна.

Вы говорите, что вы собираетесь проверить базу данных на уникальность; вы не говорите, что вы собираетесь делать, если есть столкновение. Вы также не говорите, что вы собираетесь делать с условиями гонки; предположим, что одновременно создаются два встречных идентификатора ордера, ни в базе данных, ни в базе данных. Вы запрашиваете базу данных по двум различным темам независимо от того, является ли элемент уникальным; это. Затем вы вводите оба значения, и уникальность была нарушена, хотя проверка была выполнена.

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

Кстати, в течение многих лет я задал вопрос об этом вопросе как вопрос технического интервью. Я заметил сильную корреляцию между множеством людей, которые пытаются использовать время как источник уникальности и набор людей, которые не нанимаются. Время ужасно источник уникальности; В то же время может произойти много разных вещей.

Что еще хуже, это использование случайных чисел. Случайные числа - еще один источник уникальности, чем временные метки. Предположим, у вас есть генератор случайных чисел, который генерирует случайные 32-битные целые числа для идентификаторов заказов. Сколько заказов вам нужно, прежде чем шансы лучше, чем пятьдесят пятьдесят, что вы создали два заказа с одинаковым идентификатором? Ответ удивляет многих людей: это всего около 77 тысяч, прежде чем существует 50% вероятность того, что вы создали два ордера с одинаковым номером (и только 9300, пока не будет 1% -ный шанс.)

Помните: что вы после этого гарантия уникальности. Не вероятный уникальность, но гарантия на железо, что один номер заказа относится только к одному заказу. Если это то, что вам нужно, тогда убедитесь, что вы это реализуете.

0
+1

Если вы предполагаете, что идентификатор заказа произвольно генерируется с использованием истинной случайности, это * опасно ужасная идея.Шансы получить столкновение между двумя действительно случайными 32-разрядными номерами повышаются до> 50% после всего 77000 попыток! –

+0

@ Эрик: Вы правы, я не предлагаю, чтобы идентификатор заказа # был случайным образом сгенерирован, но только то, что генерирование числа должно быть информировано о подводных камнях таких операций, как вы указали. Теория случайных чисел - хорошее место, чтобы найти такие подводные камни, чтобы их можно было избежать. –

Смежные вопросы