Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 как лучше всего блокировать строчку при бронировании билетов.  [new]
Albatross
Member

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

Процедура после селекта помечает строчку как заблокированную в таблице (соответствующее поле).
Как лучше всего предотвратить ситуации, когда в промежутке между блокировкой и селектом кто-то другой заблокирует?
Если ставить REPETEABLE READ, то возникают дедлоки.
Может, что-то другое нужно? Я читал где-то, что курсоры для этого используют обновляемые.
Вроде даже вопрос в тесте микрософта есть на эту тему.

MS SQL 2008R2
11 июл 13, 15:33    [14553168]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
Сначала update, который "помечает строчку как заблокированную в таблице (соответствующее поле)", потом все остальное.
11 июл 13, 15:42    [14553237]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Albatross
Member

Откуда:
Сообщений: 1001
Гавриленко Сергей Алексеевич,

Там вот такая тонкость...
вот я нашел строчку....
апдейтил её
а как мне её потом селектить?
я же в UPDATE не могу написать
@rowid = rowid или что-то подобное.... чтобы потом в селекте использовать.
11 июл 13, 15:44    [14553258]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
Output же.
11 июл 13, 15:44    [14553260]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Albatross
Member

Откуда:
Сообщений: 1001
Можно, конечно, в таблице добавить поле guid, в начале процедуры его генерить, в UPDATE присваивать, а потом по этому guid делать отбор, но как-то криво.
11 июл 13, 15:45    [14553269]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Albatross
Member

Откуда:
Сообщений: 1001
Гавриленко Сергей Алексеевич
Output же.

Во, кажется оно.
Спасибо!
11 июл 13, 15:50    [14553302]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
gwergwerg
Guest
фыAlbatross,

чтобы в repetable read было меньше дедлоков, нужно к ресурсам обращаться в одинаковом порядке.
11 июл 13, 17:00    [14553879]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
iap
Member

Откуда: Москва
Сообщений: 47145
Albatross
Гавриленко Сергей Алексеевич,

Там вот такая тонкость...
вот я нашел строчку....
апдейтил её
а как мне её потом селектить?
я же в UPDATE не могу написать
@rowid = rowid или что-то подобное.... чтобы потом в селекте использовать.
Не понял.
UPDATE случайной строки что ли?
Или, всё-таки, конкретной? С указанием ID. Который, стало быть, известен.
11 июл 13, 17:05    [14553907]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Cygapb-007
Member

Откуда:
Сообщений: 1677
ээ.. вообще-то, между сложным получением ID и выполнением UPDATE, наверное, может вклиниться (со своим UPDATE) более шустрый клиент ?
11 июл 13, 17:56    [14554290]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Konst_One
Member

Откуда:
Сообщений: 11625
что за бред?
Cygapb-007
ээ.. вообще-то, между сложным получением ID и выполнением UPDATE, наверное, может вклиниться (со своим UPDATE) более шустрый клиент ?
11 июл 13, 17:56    [14554294]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Konst_One
Member

Откуда:
Сообщений: 11625
declare @id int
update table set stateid=2, @id= id where id=1

select @id
11 июл 13, 17:57    [14554301]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
X-Cite
Member

Откуда: Минск
Сообщений: 1843
Что если попробовать положить блокировку на табоицу во время Select
WITH (TABLOCKX)
WITH (TABLOCK, , ROWLOCK)
и т.п.
11 июл 13, 18:32    [14554473]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
X-Cite
Что если попробовать положить блокировку на табоицу во время Select
WITH (TABLOCKX)
WITH (TABLOCK, , ROWLOCK)
и т.п.
А почему не на базу целиком? Или сервер в single user вообще запустить?
11 июл 13, 18:36    [14554485]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Cygapb-007
Member

Откуда:
Сообщений: 1677
Konst_One
что за бред?
Cygapb-007
ээ.. вообще-то, между сложным получением ID и выполнением UPDATE, наверное, может вклиниться (со своим UPDATE) более шустрый клиент ?
Вы считаете, бред? Вспомните:
Albatross
сложным селектом из таблицы выбирается строчка и отдается пользователю, с учетом того, что она не заблокирована.
Процедура после селекта помечает строчку как заблокированную в таблице (соответствующее поле).
Пример:
declare @id int
select @id=id from myTable where f_locked=0
...
declare @processedID table (id int)
...
update myTable 
  set f_locked=1
  output inserted.id into @processedID
  where id=@id and f_locked=0
print @@rowcount
По-вашему, @@rowcount всегда будет 1?
11 июл 13, 19:27    [14554620]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Cygapb-007
По-вашему, @@rowcount всегда будет 1?
@@rowcount надо проверять всегда.
И если оно неправильное (!= 1) то надо обработать (проверить и выдать "Уже забронировано, найдите другое посадочное место", а на клиенте обновить ... кароче сами понимаете)
12 июл 13, 16:30    [14559326]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Cygapb-007
update myTable 
  set f_locked=1
  output inserted.id into @processedID
  where id=@id and f_locked=0
По-вашему, @@rowcount всегда будет 1?
А где идентификатор, кто заблокировал?
Ну это вы решайте.

Cygapb-007
declare @id int
select @id=id from myTable where f_locked=0
А это что за уйня?
update должен сразу быть, первым. А далее уже по обстановке - снятие брони или покупка.
12 июл 13, 16:35    [14559366]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Cygapb-007
Member

Откуда:
Сообщений: 1677
Mnior
А это что за уйня?
update должен сразу быть, первым. А далее уже по обстановке - снятие брони или покупка.

честно говоря, устал кивать на старттопик 14553168
все вопросы на эту тему - к ТСу
12 июл 13, 16:41    [14559414]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Cygapb-007
честно говоря, устал кивать на старттопик 14553168
все вопросы на эту тему - к ТСу
Какие тут могут быть вопросы?!
ТС должен понять базовые основы.
Если он упёрся в 2+2=5, поставить в угол.
Хотя судя по всему он не упёрся, а всё дело во взаимопонимании.
12 июл 13, 18:40    [14560194]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
shandai
Member

Откуда:
Сообщений: 44
А что если воспользоваться добавлением в таблицу столбца с типом данных rowversion (timestamp).
В момент запроса select фиксировать время начало запроса, затем при подвтерждении выбора билета брать значение из поля "rowversion" и в случае если оно меньше времени начала запроса, то делать обновление Update и фиксировать билет как проданый.
Можно еще и временные таблицы попытаться использовать и может даже транзакции.
Другое дело если нужно обязательно блокировать (исключать) кем-то выбранные select-ом записи одного пользователя от другого, что бы они даже небыли ему видны.
15 июл 13, 07:59    [14565005]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
shandai
Member

Откуда:
Сообщений: 44
И еще в догонку, може я не совсем уловил суть задачи но...

Апдейтить сразу выбираемые записи, и потом пользователю их вывести.
К примеру в таблице есть столбец lock_user, если в нем занчение не равно 0, оно свободно.
Теперь есть процедура, котоая вернет пользователю нужные данные и сразу их заблокирует:

update table_
set table_.lock_user = @user_id -- @user_id идентификатор текущего пользователя
where table_.id in (select table_.id from table_ where table_.lock_user = 0 /* ADN и дургие условия*/)
--- данным запросом обнволили все записи нашего пользователя, которые удвлетворяли его запросу

--- теперь их засунем в во временную таблицу и дадим пользователю
IF OBJECT_ID('tempdb..##tbl_tmp_user_id') IS NOT NULL -- удаляем временную таблицу на случай если она существовала
   drop table ##tbl_tmp_cont_gd_namber

select * into ##tbl_tmp_user_id from table_ where table_.lock_user = @user_id

--- выводим пользователю данные, которые он отобрал
select * from ##tbl_tmp_user_id 
15 июл 13, 08:24    [14565036]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
StarikNavy
Member

Откуда: Москва
Сообщений: 2415
shandai
Теперь есть процедура, котоая вернет пользователю нужные данные и сразу их заблокирует:


а пользователь после этого идет пить чай (на пару часов), без подтверждения бронирования
15 июл 13, 09:32    [14565229]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Гость333
Member

Откуда:
Сообщений: 3683
shandai,

Ваш код ужасен

shandai
update table_
set table_.lock_user = @user_id -- @user_id идентификатор текущего пользователя
where table_.id in (select table_.id from table_ where table_.lock_user = 0 /* ADN и дургие условия*/)
--- данным запросом обнволили все записи нашего пользователя, которые удвлетворяли его запросу

--- теперь их засунем в во временную таблицу и дадим пользователю
IF OBJECT_ID('tempdb..##tbl_tmp_user_id') IS NOT NULL -- удаляем временную таблицу на случай если она существовала
   drop table ##tbl_tmp_cont_gd_namber --Проверяем существование одной таблицы, а дропаем другую?

select * into ##tbl_tmp_user_id from table_ where table_.lock_user = @user_id

...а в это время другой процесс дошёл до инструкции "drop table"... 

--- выводим пользователю данные, которые он отобрал
--- Либо получим ошибку Invalid object name '##tbl_tmp_user_id' - это в лучшем случае
--- Либо получим данные другого процесса - это в худшем случае
select * from ##tbl_tmp_user_id 

Почему используется глобальная временная таблица?
15 июл 13, 10:41    [14565768]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
Гость333
Member

Откуда:
Сообщений: 3683
StarikNavy
shandai
Теперь есть процедура, котоая вернет пользователю нужные данные и сразу их заблокирует:


а пользователь после этого идет пить чай (на пару часов), без подтверждения бронирования

Вы код видели? Там фокус не в том, что "уйдёт на пару часов". А в том, что пользователь может вообще передумать покупать билет. То есть должен быть предусмотрен процесс, снимающий броню по прошествии какого-то времени (скажем, 10 минут), в течение которого билеты не были оплачены.

Сама идея-то у shandai верная, но реализация печальна.
15 июл 13, 10:48    [14565812]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
StarikNavy
Member

Откуда: Москва
Сообщений: 2415
Гость333
Вы код видели? Там фокус не в том, что "уйдёт на пару часов". А в том, что пользователь может вообще передумать покупать билет.

да, именно на это и намекал
15 июл 13, 11:36    [14566262]     Ответить | Цитировать Сообщить модератору
 Re: как лучше всего блокировать строчку при бронировании билетов.  [new]
shandai
Member

Откуда:
Сообщений: 44
Гость333
shandai,

Ваш код ужасен

[quot shandaiПочему используется глобальная временная таблица?

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

Возможно, тогда единственным решением, в котором полностью отсутсвуют описанные грабли, как раз и будет поле в таблице с типом данных rowversion (timestamp).
В момент запроса select фиксировать время начало запроса, затем при подвтерждении выбора билета брать значение из поля "rowversion" и в случае если оно меньше времени начала запроса, то делать обновление Update и фиксировать билет как проданый.
Можно еще и временные таблицы попытаться использовать и может даже транзакции.
Другое дело если нужно обязательно блокировать (исключать) кем-то выбранные select-ом записи одного пользователя от другого, что бы они даже небыли ему видны.
15 июл 13, 11:49    [14566386]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить