Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Блокировка выполнения хранимой процедуры  [new]
Игорь_UUS
Member

Откуда: г. Екатеринбург
Сообщений: 670
Добрый день

Предположим 5 сеансов работают с одной базы. Первый сеанс начал выполнение хранимой процедуры в которой был вызван BEGIN TRANSACTION, вопрос: как запретить выполнение хранимой процедуры всем остальным сеансам.. я бы сказал запретить параллельное выполнение, т.е. останавливаем выполнение до тех пор, пока идёт выполнение другим сеансом?


Суть такая, идёт приём телефонных звонков на 5-ти рабочих местах, АТС направляет телефонный вызов параллельно на все рабочие места, тот кто первый ответит, тот и начинает общение, у остальных происходит сброс. Сделано так, что при получении вызова, "db-клиент" сохраняет телефонный звонок вызывая хранимую процедуру. В самой хранимке имеется проверка, существует ли запись с таким номером телефоном в данный момент времени, если уже существует, то хранимка прекращает выполнение. Сейчас баг в том, что "раз через раз" при получении телефонного вызова происходит вставка 5-ти строк в БД, хотя должна быть одна.

Нашёл возможное место ошибки:

SET NOCOUNT ON;

SET @Result = 0

BEGIN TRANSACTION

DECLARE @Ret INT
DECLARE @Direction INT = [dbo].[SIP_DirectionIn]()
DECLARE @CallKey INT
-- Исключение создание повторного вызова при параллельном вызове.
SET @CallKey = (
  SELECT
    [Key]
  FROM
    [SIP_Calls]
  WHERE
    [Phone] = @Phone AND [Direction] = @Direction AND [CreatedBySipPhone] = 1 AND 
    [StartedConversation] IS NULL AND DATEDIFF(SECOND, [CallDate], [dbo].[CORE_ServerDateToBranchDate]()) < 300
)

IF NOT @CallKey IS NULL
BEGIN
  COMMIT TRANSACTION
  SET @Result = @CallKey
  RETURN 0
END

...
... Далее если телефонного вызова с таким номером нет, то идёт создание записи
...


"Клиент" - закрытое скомпелированное ПО, но могу отредактировать бизнес логику... подскажите что тут лучше сделать?
30 апр 19, 11:11    [21875337]     Ответить | Цитировать Сообщить модератору
 Re: Блокировка выполнения хранимой процедуры  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31354
Игорь_UUS
вопрос: как запретить выполнение хранимой процедуры всем остальным сеансам.. я бы сказал запретить параллельное выполнение, т.е. останавливаем выполнение до тех пор, пока идёт выполнение другим сеансом?
Использовать спкециально предназначенные для этого процедуры sp_getapplock / sp_releaseapplock
30 апр 19, 11:14    [21875340]     Ответить | Цитировать Сообщить модератору
 Re: Блокировка выполнения хранимой процедуры  [new]
invm
Member

Откуда: Москва
Сообщений: 9344
Игорь_UUS
-- Исключение создание повторного вызова при параллельном вызове.
SET @CallKey = (
  SELECT
    [Key]
  FROM
    [SIP_Calls]
  WHERE
    [Phone] = @Phone AND [Direction] = @Direction AND [CreatedBySipPhone] = 1 AND 
    [StartedConversation] IS NULL AND DATEDIFF(SECOND, [CallDate], [dbo].[CORE_ServerDateToBranchDate]()) < 300
)

IF NOT @CallKey IS NULL
BEGIN
  COMMIT TRANSACTION
  SET @Result = @CallKey
  RETURN 0
END
Ничего это "исключение" не исключает.
Такие вещи делаются через merge и без всяких предварительных селектов
merge into [SIP_Calls] t with (serializable)
using
 (values (@Phone, @Direction)) s(Phone, Direction) on t.Phone = s.Phone AND t.Direction = s.Direction AND t.CreatedBySipPhone = 1 AND 
    t.StartedConversation IS NULL AND DATEDIFF(SECOND, t.CallDate, dbo.CORE_ServerDateToBranchDate()) < 300
when not matched then
 insert ...
when matched then
 update
  set @CallKey = t.Key;

IF @CallKey IS not NULL
BEGIN
  COMMIT TRANSACTION
  SET @Result = @CallKey
  RETURN 0
END

И не придется сериализовать вызов процедуры.
30 апр 19, 11:39    [21875368]     Ответить | Цитировать Сообщить модератору
 Re: Блокировка выполнения хранимой процедуры  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7752
Игорь_UUS,

используйте грязные чтения. Есть риск, но небольшой. Зато самая простая реализация.
30 апр 19, 14:34    [21875566]     Ответить | Цитировать Сообщить модератору
 Re: Блокировка выполнения хранимой процедуры  [new]
uaggster
Member

Откуда:
Сообщений: 826
Игорь_UUS
Добрый день

Предположим 5 сеансов работают с одной базы. Первый сеанс начал выполнение хранимой процедуры в которой был вызван BEGIN TRANSACTION, вопрос: как запретить выполнение хранимой процедуры всем остальным сеансам.. я бы сказал запретить параллельное выполнение, т.е. останавливаем выполнение до тех пор, пока идёт выполнение другим сеансом?

Создайте отдельную таблицу.
Далее, внутри транзакции произведите апдейт какой-либо записи этой таблицы, With (TABLOCKX, UPDLOCK), первой операцией.
Далее, внутри транзакции, расположите свои апдейты и т.д.
Собственно всё.
30 апр 19, 14:51    [21875596]     Ответить | Цитировать Сообщить модератору
 Re: Блокировка выполнения хранимой процедуры  [new]
aleks222
Member

Откуда:
Сообщений: 952
uaggster
Создайте отдельную таблицу.
Далее, внутри транзакции произведите апдейт какой-либо записи этой таблицы, With (TABLOCKX, UPDLOCK), первой операцией.
Далее, внутри транзакции, расположите свои апдейты и т.д.
Собственно всё.

Стисняюсь спросить...
А чем этот геморрой лучше sp_getapplock / sp_releaseapplock?
30 апр 19, 18:53    [21875880]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить