Генерация уникальных номеров счетов - рекурсивный вызов - PullRequest
5 голосов
/ 19 сентября 2008

Привет, мне нужно сгенерировать 9-значный уникальный номер счета. Вот мой псевдокод:

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    if the account number already exists in the DB 
        call generateAccNo()    /* recursive call */
    else
        return new accout number
    end if

end function

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

Приведет ли это к утечкам памяти (PHP 5 под apache)?

Является ли это приемлемым способом решения этой проблемы?

Спасибо за ваш вклад.

Ответы [ 10 ]

8 голосов
/ 19 сентября 2008

Вы понимаете, что это вполне может вызвать переполнение стека, верно? По мере увеличения количества клиентов увеличивается вероятность не найти приемлемый номер счета.

Кроме того, почему вы не можете просто использовать последовательные номера счетов и просто увеличивать их на единицу каждый раз? При таком подходе вам просто нужно прочитать максимальный идентификатор, который в данный момент находится в базе данных, и просто увеличить его.

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

Вы действительно должны рассмотреть другой подход:
Я настоятельно рекомендую просто увеличивать номер клиента каждый раз, когда вы создаете клиента. На самом деле, если вы правильно настроили свою базу данных (с автоинкрементом в столбце id), вам даже не нужно будет устанавливать id. Идентификатор будет установлен для вас при каждом добавлении нового клиента.

3 голосов
/ 19 сентября 2008

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

. GUID

Если требуется действительно уникальный идентификатор с минимальными усилиями, рассмотрите GUID, ваша БД, скорее всего, сможет назначить вас при вставке, если не создаст ее в коде. Он гарантированно уникален, хотя и не очень удобен для пользователя. Однако в сочетании с последовательным AccountRecordId, сгенерированным БД при вставке, вы получили бы сплошную комбинацию

. Составной ключ: Случайный + Последовательный

Один из способов удовлетворить все потребности, хотя на первый взгляд он кажется немного запутанным, - это создать составной номер счета из последовательного ключа БД из 5 цифр (или более), а затем еще 5 цифр случайности. Если бы случайное число было продублировано, это не имело бы значения, поскольку последовательный идентификатор гарантировал бы уникальность всего номера счета

2 голосов
/ 19 сентября 2008

Здесь нет необходимости использовать рекурсивный вызов. Запустите простой цикл while в тестировании функции на предмет отсутствия в качестве условия, например,

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    while ( the account number already exists in the DB ) {
         generate new account number;
    }
    return new account number

end function

Произвольное генерирование и тестирование - это неоптимальный подход к генерированию уникальных номеров счетов, хотя, если этот код предназначен для чего-то другого, кроме игрушки.

1 голос
/ 19 сентября 2008

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

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

1 голос
/ 19 сентября 2008

Последовательное генерирование номеров счетов - это угроза безопасности - вам нужно найти другой алгоритм для этого.

1 голос
/ 19 сентября 2008

Кажется, хорошо, но я думаю, что вам нужно какое-то условие смерти, сколько раз вы позволите этому пройти, прежде чем сдаться?

Я знаю, что это кажется маловероятным с огромным диапазоном номеров, но что-то может пойти не так, что просто вернет вас к предыдущему вызову, который снова вызовет себя, ad-nauseum.

0 голосов
/ 19 сентября 2008

Почему бы не обработать базу данных? В SQL Server у вас может быть просто столбец идентификаторов, который начинается с 100000000. Или вы можете использовать sql в любой имеющейся у вас базе данных. Просто получите максимальный идентификатор плюс 1.

0 голосов
/ 19 сентября 2008

Почему бы и нет:

lock_db
do
    account_num <= generate number
while account_num in db

put row with account_num in db

unlock_db
0 голосов
/ 19 сентября 2008

Вы можете поместить это в цикл while:

function generateAccNo()

    while (true) {    

      generate an account number between 100,000,000 and 999,999,999

      if the account number already exists in the DB 
          /* do nothing */
      else
          return new accout number
      end if
    }

end function
0 голосов
/ 19 сентября 2008

Вам не нужно использовать рекурсию здесь. Простой цикл был бы таким же быстрым и занимал бы меньше места в стеке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...