Как генерировать уникальный номер заказа?

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

int customerId = 10000000;

long ticks = DateTime.UtcNow.Ticks;

long orderId = customerId + ticks;

int orderNumber = orderId.GetHashCode();

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

8
задан Junior Developer 15 February 2010 в 16:06
поделиться

6 ответов

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

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

7
ответ дан 5 December 2019 в 04:37
поделиться

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

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

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

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

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

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

15
ответ дан 5 December 2019 в 04:37
поделиться

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

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

0
ответ дан 5 December 2019 в 04:37
поделиться

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

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

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

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

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

Если вам действительно нужно использовать числовой идентификатор, и вы готовы отказаться от простого масштабирования приложения на нескольких серверах, вы можете использовать автоматически увеличивающийся глобальный номер для предоставления уникальный ключ. Вам нужно будет заполнить это число следующим доступным значением (макс. + 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 ); }
}


РЕДАКТИРОВАТЬ: В наши дни веские причины для генерации уникальных идентификаторов на уровне вашего приложения, а не в базе данных, очень редки. Вам действительно следует использовать возможности, которые предоставляет база данных.

25
ответ дан 5 December 2019 в 04:37
поделиться

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

0
ответ дан 5 December 2019 в 04:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: