Форум программистов, компьютерный форум, киберфорум
Microsoft SQL Server
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10

Обеспечение последовательного (согласно очереди) доступа к таблице-справочнику

11.10.2024, 09:47. Показов 2071. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую!

Вводные:
• некоторый блок кода (БК) начал повторятся в разных ХП (П1, П2).
• я хочу его оформить в отдельную ХП (ОП: отдельная процедура).
• в каждой ХП БК работает с временными таблицами (ВТ) #tmp внутри этой ХП и обращается к единой справочной таблице Dict.
• для работы БК нужно 3 поля (условные названия): ID Int, Str VarChar (50), Ins VarChar(1).

БК делает 3 основных действия:
1. проверяет ID и Str по Dict.
2. при нахождении, заполняет Ins значением из Dict.
3. при ненахождении заполняет Dict этими ненайденными (пополняет словарь).

При вызове ОП из П1/П2, ОП "видит" ВТ, созданные в П1/П2.
На этом я и хочу построить логику.

То есть, ОП будет без параметров. Работать будет с #TempName из вызывающей ХП, с полями, имена которых известны.
Вопрос в том, как, в этом случае, правильно разрулить многопоточность?

Что именно нужно обеспечить: в ситуации, когда есть несколько параллельных вызовов П1 и/или П2, та ХП, что первой вызвала ОП и, в ней, "дошла" до получения данных из Dict, должна блокировать Dict (например, от других экземпляров ХП), пока не закончит работу с ней.

Надеюсь, более-менее понятно объяснил
Если можно, то хотелось бы обойтись без явных (ручками) блокировок.
Явные транзакции допускаются.

Достаточно ли будет просто обернуть блок получения данных из Dict и вставки новых данных (если они есть) в Dict — в явную транзакцию (Begin Tran … Commit)?
Будет ли, в таком случае, очередной экземпляр ОП ждать, пока Dict "освободится", чтобы получить из него самые "свежие" данные?

И правильно ли я понимаю, что каждый экземпляр ОП будет работать со своим экземляром #tmp из вызывающей ХП? И разруливать тут ничего не нужно.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
11.10.2024, 09:47
Ответы с готовыми решениями:

записать в файл последовательного доступа N произвольных натуральных чисел.переписать в другой файл последовательного доступа те элементы ,которые кра
записать в файл последовательного доступа N произвольных натуральных чисел.переписать в другой файл последовательного доступа те элементы...

Записать в файл f последовательного доступа N натуральных чисел. Получить в другом файле последовательного дос
Записать в файл f последовательного доступа N натуральных чисел. Получить в другом файле последовательного доступа все компоненты файла f ,...

Привязка в таблице к таблице справочнику
Пытаюсь сделать привязку в DataGrid, создал класс модели и в ней коллекцию ObservableCollection , привязал таблицу к коллекции. Всё в...

24
1304 / 358 / 97
Регистрация: 14.10.2022
Сообщений: 1,089
11.10.2024, 09:53
Лучший ответ Сообщение было отмечено Jack Famous как решение

Решение

Цитата Сообщение от Jack Famous Посмотреть сообщение
Если можно, то хотелось бы обойтись без явных (ручками) блокировок.
Ну, если sp_getapplock не нравится, накладывай with (tablock, holdlock) в транзакции, при оперировании с данными #TempName.

Добавлено через 44 секунды
Цитата Сообщение от Jack Famous Посмотреть сообщение
Достаточно ли будет просто обернуть блок получения данных из Dict и вставки новых данных (если они есть) в Dict — в явную транзакцию?
Будет ли, в таком случае, очередной экземпляр ОП ждать, пока Dict "освободится", чтобы получить из него самые "свежие" данные?
Да. with (tablock, holdlock).
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
11.10.2024, 09:56  [ТС]
uaggster, большое спасибо
Цитата Сообщение от uaggster Посмотреть сообщение
накладывай with (tablock, holdlock) в транзакции, при оперировании с данными #TempName
а точно именно с #TempName? Или, всё-таки с Dict, которая одна для всех?
0
1304 / 358 / 97
Регистрация: 14.10.2022
Сообщений: 1,089
11.10.2024, 10:03
Да откуда ж я знаю.
Текст покажи?

Общая идеология:
1. Открываешь транзакцию.
2. Читаешь/пишешь из некоего общего ресурса with (tablock, holdlock). Это аналог serializable, но захватывается только одна таблица (... и ее форейгн-кеи, если установлена декларативная ссылочная целостность).
Всё. Все остальные курят до конца транзакции.

"Кроме мордобитиев - никаких чудес!" (С) ВСВ.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
11.10.2024, 10:14  [ТС]
Цитата Сообщение от uaggster Посмотреть сообщение
Все остальные курят до конца транзакции.
то, что нужно!
Вот тут пример нашёл с пояснением.
Цитата Сообщение от uaggster Посмотреть сообщение
Текст покажи?
Я правда пытался, но пока есть только это =)
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
-- ================================================================================================
Create Or Alter Procedure test.SP1
As
Begin
    Delete #t Where I = 3;
    WaitFor Delay '00:00:00.003'
    Insert #t(V) Values ('New1'), ('New2');
End
Go
-- ================================================================================================
Create Or Alter Procedure test.SP2
(
    @nPack Int
)
As
Begin
    Create Table #t
    (
        S   Int         Default @@SPID      ,
        P   Int                             ,
        I   Int         Identity(1, 1)      ,
        D   DateTime    Default GetDate()   ,
        V   VarChar(100)
    );
    WaitFor Delay '00:00:00.003'
    Insert #t(P, V) Values (@nPack, 'abc'), (@nPack, 'ABC'), (@nPack, '456'), (@nPack, '00215'), (@nPack, 'NA');
    
    Select * From #t;
    Exec test.SP1
    Select * From #t;
End
Go
-- ================================================================================================
Exec test.SP2;
-- ================================================================================================
Declare @i Int = 1;
While (@i <= 3)
    Begin
        Exec test.SP2 @i;
        Set @i = @i + 1;
    End
-- ================================================================================================
Drop Procedure If Exists test.SP1, test.SP2;
Go
-- ================================================================================================


UPD:
uaggster, скажите, а "монопольный" хинт TABLOCKX предпочтительнее TABLOCK, в этом случае, или по барабану?
0
1304 / 358 / 97
Регистрация: 14.10.2022
Сообщений: 1,089
11.10.2024, 11:56
Цитата Сообщение от Jack Famous Посмотреть сообщение
а "монопольный" хинт TABLOCKX предпочтительнее TABLOCK, в этом случае, или по барабану?
https://stackoverflow.com/ques... s-tablockx
0
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
11.10.2024, 13:24  [ТС]
uaggster, я это читал, но не понял до конца) можно своими словами?
0
3614 / 2135 / 756
Регистрация: 02.06.2013
Сообщений: 5,169
11.10.2024, 20:56
В чем смысл holdlock совместно с блокировкой уровня таблицы?

Цитата Сообщение от Jack Famous Посмотреть сообщение
Вопрос в том, как, в этом случае, правильно разрулить многопоточность?
Зачем вообще как-то отдельно разруливать многопоточность?

Для выстраивания вызовов ХП в очередь пользуются sp_getaoolock уровня транзакции
Тогда не придется насиловать сервер монопольными блокировками
1
3614 / 2135 / 756
Регистрация: 02.06.2013
Сообщений: 5,169
12.10.2024, 11:11
Цитата Сообщение от invm Посмотреть сообщение
В чем смысл holdlock совместно с блокировкой уровня таблицы?
Имеется в виду tablockx
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
14.10.2024, 09:35  [ТС]
Цитата Сообщение от invm Посмотреть сообщение
Зачем вообще как-то отдельно разруливать многопоточность?
в ХП, вызываемой из других ХП используется вот такой блок. Там происходит выборка данных из таблицы SKU.NumMers и её пополнение.
Хотелось бы, чтобы она блокировалась с начала получения данных и до окончания пополнения — чтобы все другие обращения получали самые свежие данные и не пытались добавить в эту таблицу то, что в параллельном вызове только что было добавлено.
Блок кода работы со Справочником
Цитата Сообщение от invm Посмотреть сообщение
Для выстраивания вызовов ХП в очередь пользуются sp_getaoolock уровня транзакции
прошу продемонстрировать простой пример. Я, конечно, почитаю, что это, но с примером будет намного проще разобраться.
Как она блокирует и что?
sp_getapplock
0
1304 / 358 / 97
Регистрация: 14.10.2022
Сообщений: 1,089
14.10.2024, 10:13
Лучший ответ Сообщение было отмечено Jack Famous как решение

Решение

Цитата Сообщение от Jack Famous Посмотреть сообщение
прошу продемонстрировать простой пример.
Ну вот, например так:
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Begin Tran -- переключим все таблицы разом
-- Возможно только одно переключение одновременно, установим эксклюзивную блокировку
exec sp_getapplock N'act', 'Exclusive', 'Transaction', -1;
-- Переключение партиции из целевой таблицы в таблицу out и in
Select @sql = (
    Select 
          'Alter table [slice].' + QUOTENAME(aa.name) + ' switch partition ' + cast(p.num as varchar(255)) + ' to [tmp].' +  QUOTENAME(t2.NAME + N'_out')  + ' WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 10 MINUTES, ABORT_AFTER_WAIT = BLOCKERS));'
        + 'Alter table [tmp].' +  QUOTENAME(t2.NAME + N'_in') + ' switch to [slice].' + QUOTENAME(aa.name) + ' partition ' + cast(p.num as varchar(255)) + ';'
        FROM 
        sys.tables aa
        Cross join #regstamps tt
        Cross apply (Values ($partition.[fn_region_data](tt.[regstamp]))) p(num)
        Cross apply 
            (
            VALUES ('SLICE_' + aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + '_' + cast(tt.[regstamp] as nvarchar(255)) )
            ) t2(NAME)
        WHERE aa.schema_id = schema_id(N'slice')  
        For xml path(''), type).value(N'.', N'NVARCHAR(MAX)');
exec(@sql);
-- Освободим защелку
exec sp_releaseapplock N'act', 'Transaction';
Commit
В хранимой процедуре происходит переподключение секций из рядомстоящих таблиц, в которые производится заливка данных, но такое переключение требует эксклюзивной блокировки. Т.к. переключается сразу большой кусок витрины, состоящей из нескольких таблиц, лень разбираться, какая таблица когда будет заблокирована - организуем мьютекс.
Накладываем эксклюзивный лок на абстрактный ресурс "act" (ну, или производим эксклюзивную блокировку с именем act, как вам удобнее считать), а потом снимаем ее.
Вообще, думаю, exec sp_releaseapplock N'act', 'Transaction'; там не нужно, и даже вредно, но мопед не мой.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
14.10.2024, 10:33  [ТС]
uaggster, большое спасибо!
Правильно ли я понимаю, что sp_getapplock в данном примере:
0. будет ждать освобождения предыдущей такой блокировки (с тем же ключом) до талого — из-за параметра -1.
1. блокирует ВСЕ объекты, находящиеся внутри явной транзакции. Главное для меня — таблицы.
2. не должна иметь обязательно осмысленный 1-ый параметр, но он должен быть уникальным. Это текстовый ключ блокировки.
3. Не нуждается в снятии с помощью sp_releaseapplock, т.к. параметр 'Transaction', указанный при блокировке означает автоматическое снятие блокировки по окончании явной транзакции командой Commit/Rollback.
0
668 / 291 / 120
Регистрация: 12.04.2022
Сообщений: 1,000
14.10.2024, 11:00
Лучший ответ Сообщение было отмечено Jack Famous как решение

Решение

Цитата Сообщение от Jack Famous Посмотреть сообщение
а "монопольный" хинт TABLOCKX предпочтительнее TABLOCK, в этом случае, или по барабану?
Нет, не "по барабану".

TABLOCK - накладывает S-блокировку на таблицу, причем блокировка удерживается до конца исполнения инструкции.

TABLOCKХ - накладывает Х-блокировку на таблицу, причем блокировка удерживается до конца транзакции.

Что бы при TABLOCK, S-блокировка удерживалась до конца транзакции добавляется хинт holdlock.

Кликните здесь для просмотра всего текста
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use tempdb
go
 
create table t (f1 int primary key, f2 char(4000) default '1');
go
 
insert into t (f1)
select top 2 row_number() over (order by 1/0) 
 from master.dbo.spt_values
 
begin tran 
select * from t with (tablock) where f1 <= 1 
 
SELECT *  
from 
(select N'with (tablock) -  блокировка снялась') t1(a)
outer apply (
select 
resource_type ,
       object_name(resource_associated_entity_id)  as TableName ,
       request_mode ,
       request_type ,
       request_status
FROM sys.dm_tran_locks where resource_database_id = 2) t2
 
 
select * from t with (tablock, holdlock) where f1 > 1 
 
SELECT *  
from 
(select N'with (tablock, holdlock) - блокировка осталась') t1(a)
outer apply (
select 
resource_type ,
       object_name(resource_associated_entity_id)  as TableName ,
       request_mode ,
       request_type ,
       request_status
FROM sys.dm_tran_locks where resource_database_id = 2) t2
 
rollback
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
14.10.2024, 12:52  [ТС]
PaulWist, большое спасибо за подробное и понятное объяснение с примером!

UPD:
Товарищи, как вы считаете, какой из предложенных вариантов лучше подходит для решения моей задачи — TABLOCKХ или sp_getapplock?
Я пока переделал на exec sp_getapplock 'UniqName', 'Exclusive', 'Transaction', -1 (мне он кажется надёжнее) …
0
3614 / 2135 / 756
Регистрация: 02.06.2013
Сообщений: 5,169
14.10.2024, 13:00
Цитата Сообщение от Jack Famous Посмотреть сообщение
чтобы все другие обращения получали самые свежие данные и не пытались добавить в эту таблицу то, что в параллельном вызове только что было добавлено
Странное желание искусственно ограничивать конкурентность...
У вас что, бизнес-требование - манипуляции со справочником должны быть атомарными? Даже если разные процессы затрагивают непересекающиеся данные справочника?
0
668 / 291 / 120
Регистрация: 12.04.2022
Сообщений: 1,000
14.10.2024, 13:07
Цитата Сообщение от Jack Famous Посмотреть сообщение
UPD:
Товарищи, как вы считаете, какой из предложенных вариантов лучше подходит для решения моей задачи — TABLOCKХ или sp_getapplock?
Я пока переделал на exec sp_getapplock 'UniqName', 'Exclusive', 'Transaction', -1 (мне он кажется надёжнее) …
sp_getapplock - будет работать, только в случае доступа к данным через унифицированный АПИ, те дёргаются исключительно ваши ХП.

Если какой-то клиент "полезет" напрямую в табличку (например, через ODBC), то он не знает ни сном, ни духом о какой-то клиентской блокировке.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
14.10.2024, 13:35  [ТС]
invm, просто не должно возникнуть ситуации, когда пополнение справочника или получение из него данных произошло параллельно. В этом случае, ХП1 может добавить в него данные, которые ХП2 не увидела и ХП2 попытается также их добавить и получит ошибку. Это одна из недопустимых операций.
Цитата Сообщение от PaulWist Посмотреть сообщение
Если какой-то клиент "полезет" напрямую в табличку (например, через ODBC), то он не знает ни сном, ни духом о какой-то клиентской блокировке.
спасибо. В этом случае, TABLOCKХ надёжнее?
Пока что работа со справочником осуществляется только через мои ХП.

UPD:
Цитата Сообщение от Jack Famous Посмотреть сообщение
не должно возникнуть ситуации, когда пополнение справочника или получение из него данных произошло параллельно
Подробнее:
1. ХП1 и ХП2 примерно в одно время вызывают ХПс (которая работает с #t из вызывающей её ХП и Справочником)
2. ХПс1 (ХПс, вызванная из ХП1) забирает данные из справочника. Допустим, на период забора данных Справочник блокируется, но этого недостаточно.
3. ХПс2 забирает данные из Справочника строго после ХПс1.
4. ХПс1 находит в своём экземпляре #t строки, данные из которых нужно добавить в Справочник.
5. ХПс2 также находит те же строки (хотя бы часть из них) в своём экземпляре #t.
6. ХПс1 добавляет в Справочник недостающие строки.
7. ХПс2 добавляет в Справочник недостающие строки, часть из которых была добавлена ХПс1.
8. Получаем (как минимум) ошибку при добавлении данных в Справочник, т.к. там уникальный индекс по полю.

Поэтому важно блокировать Справочник с момента 1го обращения в ХПс и до конца работы с ним в ХПс. Этот блок заключён в явную транзакцию на скрине из #10.
0
3614 / 2135 / 756
Регистрация: 02.06.2013
Сообщений: 5,169
14.10.2024, 13:51
Цитата Сообщение от Jack Famous Посмотреть сообщение
6. ХПс1 добавляет в Справочник недостающие строки.
7. ХПс2 добавляет в Справочник недостающие строки, часть из которых была добавлена ХПс1.
8. Получаем (как минимум) ошибку при добавлении данных в Справочник, т.к. там уникальный индекс по полю.
Такие коллизии разруливаются инструкцией merge с хинтом serializable на целевую таблицу. Никакие дополнительные приседания не требуются.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
14.10.2024, 14:19  [ТС]
invm, я так не умею, но умею в "приседания"
Буду благодарен, если покажете
0
3614 / 2135 / 756
Регистрация: 02.06.2013
Сообщений: 5,169
14.10.2024, 14:29
Показать что? Как merge написать?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.10.2024, 14:29
Помогаю со студенческими работами здесь

Ограничение доступа к справочнику
Добрый день. Необходимо ограничить доступ к справочнику &quot;Помещения&quot;, у каждой роли свои ограничения на этот справочник. Написал...

Поиск чертежей согласно нумерованного (согласно порядка очереди) списка на листе "Данные" и копирование на лист
Здравствуйте! Кто сможет выполнить вроде как простую задачку и напишите стоимость плиз 1) на листе &quot;список&quot; пометил цветом...

Обеспечение доступа к общим ресурсам
Добрый день! Задание: Обеспечить доступ к 1 ftp-серверу (10.7.10.2) только для 1 (10.7.1.2) и 2 (10.7.2.2) площадки Обеспечить...

Обеспечение раздельного синхронизированного доступа к ресурсам
public class ThreadCar extends Thread { public void run() { new InsertTable().setVisible(true); } } - Вот...

Обеспечение доступа к локальному серверу через интернет
на локальном сервер разрабатываю мобильную версию сайта, как сделать, чтобы я смог зайти на свой локальный сервер через интернет?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru