SQL Server одновременно выполняет два запроса Insert, что приводит к получению одного и того же регистрационного номера для двух пациентов.

Я использую SQL Server 2008 R2 Express с VS2010 Ultimate C #. Это программное обеспечение клиент-серверной архитектуры для регистрации пациентов. есть 4 клиента, у которых 4 пользователя регистрируют пациентов. Когда 2 пользователя регистрируют 2 отдельных пациентов и нажимают кнопку сохранения, я делаю следующие шаги:

  1. система вытягивает следующий регистрационный номер.
  2. сохраняет запись с тем регистрационным номером. в таблицу SQL Server
  3. снова тянет следующий регистрационный нет. для следующего пациента

Если оба пользователя нажимают кнопку сохранения в одно и то же время, то SQL Server должен поместить их в очередь независимо от того, на каком лице оба пользователя одновременно нажали кнопку сохранения, SQL Server должен выполнить команду вставки первого пациента, затем сгенерируйте следующий номер, и вторая команда вставки должна выполняться сразу после первой. чтобы второй запрос мог получить следующий регистрационный номер и затем сохранить запись. но это спасает двух пациентов с одним и тем же регистрационным номером. Я даже использовал BeginTransaction, Commit и Rollback, но все еще нахожусь в исправлении. Любая помощь будет оценена по достоинству.


person user2831374    schedule 30.09.2013    source источник
comment
Можете ли вы добавить код генератора регистрационного номера и вставку?   -  person sino    schedule 30.09.2013
comment
Используйте поле Identity или GUID на клиентах, если вам нужно более экстремальное решение.   -  person Chris    schedule 30.09.2013
comment
Я согласен с @Chris - все, что вы катите самостоятельно, не будет работать при таких одновременных нагрузках. Используйте столбец идентичности - хватит пытаться заново изобрести колесо!   -  person Bridge    schedule 30.09.2013
comment
Я использую поле в отдельной таблице с именем RegNo и ByDefault, в котором я сохранил 1. когда я сохраняю запись, я читаю это поле и увеличиваю его на 1, а также сохраняю запись и обновляю это поле.   -  person user2831374    schedule 30.09.2013
comment
Цель использования отдельного поля в отдельной таблице и отказа от столбца «Идентификационные данные» заключается в том, что я не могу сбросить идентификатор до 1 после того, как финансовый год подходит к концу, поэтому я использую поле с именем RegNo в таблице регистрации пациентов и Я создал отдельную таблицу с системой имен и полем RegNo. Системная таблица содержит только 1 поле, то есть RegNo, и я обновляю его после сохранения каждой записи, увеличивая ее на 1   -  person user2831374    schedule 30.09.2013
comment
Если вы сбросите число до 1 в конце финансового года, разве вы не получите кучу дубликатов ключей при ошибках вставки? Нет ли каких-либо записей, которые вы вставляете, не противоречат тем, которые вы вставили в предыдущем финансовом году?   -  person DaveH    schedule 30.09.2013
comment
Когда вы говорите «тогда SQL Server должен поставить их в очередь», вы имеете в виду, что приложение было разработано для этого, или это ваше ожидание того, как базы данных должны работать? Если последнее, то, боюсь, ваше предположение неверно.   -  person Rikalous    schedule 30.09.2013
comment
См. ответ Ремуса Русану здесь, который точно описывает как действовать, чтобы правильно и безопасно обрабатывать ручные последовательности.   -  person marc_s    schedule 30.09.2013


Ответы (1)


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

Один из подходов - сделать следующее

  • начать транзакцию
  • обновить следующий регистрационный номер (добавив к нему 1)
  • прочтите значение
  • используйте его во вставке
  • совершить

Первоначальное обновление блокирует строку, содержащую следующий регистрационный номер, не позволяя другим потокам читать ее. «Другой» поток будет ждать снятия блокировки (образуя очередь, которую вы упомянули в своем сообщении), а затем продолжит, выделяя следующий регистрационный номер при вставке.

person DaveH    schedule 30.09.2013
comment
Я согласен с этим ответом, эта тема также подробно обсуждается здесь: stackoverflow.com/questions/1683829/ - person Damon; 30.09.2013
comment
Спасибо, Дэйв. Я использую тот же поток, который вы упомянули в своем сообщении. Я начинаю транзакцию, выбираю поле RegNo, увеличиваю его на 1, сохраняю запись пациента, затем фиксирую ее. но все же он дублирует номер. Я понятия не имею, почему это происходит. на самом деле это не должно - person user2831374; 30.09.2013
comment
Не читайте его, а затем обновляйте - чтение не блокирует строку. Сначала обновите его, затем прочтите значение. Обновление блокирует строку, что означает, что другой поток не может прочитать ее, пока транзакция не будет зафиксирована. - person DaveH; 30.09.2013
comment
хорошо, позвольте мне попробовать это, я обновлю его до следующего нет. тогда я прочитаю это. просто убедитесь, что еще одна вещь: если 2 пользователя делают это одновременно, тогда sql обязательно поставит их в очередь. это так? - person user2831374; 30.09.2013
comment
если два пользователя делают это одновременно, один из них получит блокировку, а другой будет ждать снятия блокировки. Обычно это не называется очередью, но именно это и происходит. - person DaveH; 30.09.2013
comment
я очень ценю вашу помощь, Дэйв. БОГ БЛАГОСЛОВЛЯЕТ ТЕБЯ, МОЙ СЫН; p - person user2831374; 30.09.2013