|
1С взаимоблокировки при записи в регистр. | ☑ | ||
---|---|---|---|---|
0
ejikbeznojek
14.10.14
✎
14:14
|
Добрый день.
Имеется беда с которой борюсь уже 2ю неделю 8((( Есть самописная конфигурация 8.1 . База скулёвая. Есть Документ формирующий записи в регистр сведений. И есть 20 компьютеров с которых эти документы очень быстро создают. Могут раз в 20 секунд документ создавать с каждого компа. В документ сканируется товар в количестве 1-3000 коробок. И на каждую коробку создаётся запись в регистре сведений.(т.е. при проведении документа может создаваться 1-3000 записей в регистре) Соответственно у меня появилась беда со взаимоблокировками. Я пытался её решить несколькими путями: 1. Создал константу с типом булева. И перед записью в регистр сначала проверял, есть ли галка. Если есть то ждал 60 секунд или пока не снимется галка. Потом галку ставил, делал записи в регистр, галку снимал. 2. Где-то вычитал что блокируются все константы, и вместо констант сделал новый регистр из одной записи. И аналогично работал с ним. В итоге блокируется теперь новый регистр, я уже и различные попытки ставил и паузы. Теперь пишет в данной транзакции уже происходили ошибки. Код выглядит так: ///////////////////////////////чтение из регистра Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 ИнформацияШКЛН.НомерКоробки КАК НомерКоробки |ИЗ | РегистрСведений.ИнформацияШКЛН КАК ИнформацияШКЛН |ГДЕ | ИнформацияШКЛН.ВидНакладной = &ВидНакладной | И ИнформацияШКЛН.НомерНакладной = &НомерНакладной | |УПОРЯДОЧИТЬ ПО | НомерКоробки УБЫВ |АВТОУПОРЯДОЧИВАНИЕ"; Запрос.УстановитьПараметр("ВидНакладной",ДокОснование.Метаданные().Синоним); Запрос.УстановитьПараметр("НомерНакладной",ДокОснование.номер); Конст=ПолучитьКонстантуБлокировкиИнформацииШКЛН(); если Конст тогда Пока истина Цикл Пауза(); Конст=ПолучитьКонстантуБлокировкиИнформацииШКЛН(); если Конст=ложь тогда Прервать; КонецЕсли; Если ТекущаяДата()-тВремя > 60 Тогда Пауза(); УстановитьКонстантуБлокировкиИнформацииШКЛН(ложь); Пауза(); КонецЕсли; КонецЦикла; КонецЕсли; УстановитьКонстантуБлокировкиИнформацииШКЛН(Истина); Выборка = Запрос.Выполнить().Выбрать(); УстановитьКонстантуБлокировкиИнформацииШКЛН(ложь); ///////////////////////////////чтение из регистра ///////////////////////////////запись в регистр Конст=ПолучитьКонстантуБлокировкиИнформацииШКЛН(); если Конст тогда Пока истина Цикл Пауза(); Конст=ПолучитьКонстантуБлокировкиИнформацииШКЛН(); если Конст=ложь тогда Прервать; КонецЕсли; Если ТекущаяДата()-тВремя > 60 Тогда Пауза(); УстановитьКонстантуБлокировкиИнформацииШКЛН(ложь); Пауза(); КонецЕсли; КонецЦикла; КонецЕсли; УстановитьКонстантуБлокировкиИнформацииШКЛН(Истина); Для Сч = НаборЗаписей.Количество() + 1 По КоличествоКоробок Цикл Запись = НаборЗаписей.Добавить(); Запись.ШК = ТекШККоробкиЛистаНабора; Запись.ШКЛистаНабора = ШКЛистаНабора; Запись.НомерЛН = Номер; Запись.ВидНакладной = ДокОснование.Метаданные().Синоним; Запись.НомерНакладной = ДокОснование.Номер; Запись.Количество = товары.Итог("Количество"); Запись.ГруппыТоваров = ГруппыТоваров; Запись.Подразделение = ПараметрыСеанса.ЭтотУзел.Подразделение; Запись.КоличествоКоробок = КоличествоКоробок; запись.НомерКоробкиЛН = Сч; ТекНомерКоробки = ТекНомерКоробки + 1; Запись.НомерКоробки = ТекНомерКоробки; КонецЦикла; НаборЗаписей.записать(); УстановитьКонстантуБлокировкиИнформацииШКЛН(ложь); ///////////////////////////////запись в регистр Функция ПолучитьКонстантуБлокировкиИнформацииШКЛН() экспорт запрос=новый запрос; запрос.Текст= "ВЫБРАТЬ | Константы.ЗначениеРеквизита как знач |ИЗ | РегистрСведений.Константы КАК Константы |ГДЕ | Константы.ИмяКонстанты = &ИмяКонстанты"; запрос.УстановитьПараметр("ИмяКонстанты","БлокироватьРегистрШКЛН"); сч=0; пока Истина Цикл Попытка результат=запрос.Выполнить().Выгрузить(); Прервать; Исключение сч=сч+1; если сч>10 тогда Возврат Истина;КонецЕсли; КонецПопытки; КонецЦикла; если результат=Неопределено тогда возврат Истина; КонецЕсли; если результат.количество()=0 Тогда возврат ложь; иначе Возврат результат.Получить(0).знач; КонецЕсли; КонецФункции Процедура УстановитьКонстантуБлокировкиИнформацииШКЛН(значение) экспорт если значение=Истина или значение=ложь тогда сч=0; пока Истина Цикл Попытка ЗаписьВРег=РегистрыСведений.Константы.СоздатьМенеджерЗаписи(); ЗаписьВРег.ИмяКонстанты="БлокироватьРегистрШКЛН"; ЗаписьВРег.Период=ТекущаяДата(); ЗаписьВРег.ЗначениеРеквизита=значение; ЗаписьВРег.Записать(); Прервать; Исключение сч=сч+1; если сч>10 тогда Возврат;КонецЕсли; КонецПопытки; Пауза(2000); КонецЦикла; КонецЕсли; КонецПроцедуры |
|||
1
Alex_MA
14.10.14
✎
14:30
|
Совет:
Запусти консоль кластера 1С. Пытайся добиться взаимоблокировки. Отслеживай блокировки по консоли - увидишь кто кого блокирует => узнаешь какой сеанс что запустил. Дальше анализируешь выполнение операций этими двумя сеансами. Если не получается проанализировать запускай профайлер mssql. Там событие Deadlock graph - сохрани в xml и разбирай. В этом xml будет описание: запрос_1 и запрос_2, а так же блокирующиеся ресурсы. Попытайся эту информацию сопоставить с кодом 1С и исправить ошибку. Удачи |
|||
2
Alex_MA
14.10.14
✎
14:31
|
и сразу же настораживает:
ПолучитьКонстантуБлокировкиИнформацииШКЛН УстановитьКонстантуБлокировкиИнформацииШКЛН |
|||
3
ejikbeznojek
14.10.14
✎
14:32
|
Ну это функция и процедура, я их код чуть ниже написал
|
|||
4
ejikbeznojek
14.10.14
✎
14:33
|
Собственно на 99% я уверен что они и вызывают блокировку, но не пойму как этого избежать
|
|||
5
ejikbeznojek
14.10.14
✎
14:36
|
УстановитьКонстантуБлокировкиИнформацииШКЛН(Истина);
Выборка = Запрос.Выполнить().Выбрать(); УстановитьКонстантуБлокировкиИнформацииШКЛН(ложь); при выполнении "Выборка = Запрос.Выполнить().Выбрать();" ругается иногда, в данной транзакции уже происходили ошибки. |
|||
6
rsv
14.10.14
✎
14:36
|
(0) Переходите на 8.2 т.к. можно перейти в управляемый режим (понизить до read comm ) и перейти в режим разделения итогов.
|
|||
7
ejikbeznojek
14.10.14
✎
14:38
|
Я бы и рад))
Но мне сказали, что переход в ближайшие 2 года неосуществим)) |
|||
8
Alex_MA
14.10.14
✎
14:39
|
(4) суть примерно скорее такова:
1сеанс выполняет блокировку Рес_1 2сеанс выполняет блокировку Рес_2 далее 1сеанс выполняет блокировку Рес_2 2сеанс выполняет блокировку Рес_1 захват ресурсов в разном порядке из разных транзакций - подумай над этим |
|||
9
ejikbeznojek
14.10.14
✎
14:53
|
не совсем пойму.
Регистр то у меня тут 1, и в нём всего одна запись. Я задумывал, что если взаимоблокировка происходит, то отрабатывает исключение, и так 10 попыток. Если за 10 раз все попытки не успешные, то всё равно возвращается истина. |
|||
10
КартузПива
14.10.14
✎
15:20
|
(7) Погоди. Одно дело УФ, второе - смена платформы. Работать сейчас на 8.1 в толстом клиенте - верх глупости. Все уже давно перешли на 8.2.
|
|||
11
ejikbeznojek
14.10.14
✎
15:26
|
Возможно))
Но у меня руководство убедить что нужен переход не получилось. |
|||
12
Зеленый пень
14.10.14
✎
15:34
|
(10) А вот и не все.
(0) Что за цирк с константой? Ответь сначала - откуда взаимоблокировки, регистр сведений подчинен регистратору или нет? Если нет - накладывай управляемые блокировки. |
|||
13
Necessitudo
14.10.14
✎
15:36
|
Как вариант - прямые запросы.
|
|||
14
ejikbeznojek
14.10.14
✎
15:40
|
Ну я создал булеву константу. Перед записью проверяю истина ли она. Если ложь, то ставлю в константу истину и пишу в свой регистр и обратно ставлю в консту ложь.
Если истина, то в цикле жду пока не станет ложь. Ну т.е. просто индикатор можно писать в регистр или нет. Я потом всё переделал аналогично, но вместо константы регистр сведений из 1й записи. |
|||
15
ejikbeznojek
14.10.14
✎
15:42
|
Под прямыми запросами имеется ввиду
"Select нужное поле From..."? А это точно избавит от взаимоблокировок? |
|||
16
Ник второй
14.10.14
✎
15:44
|
(6) Это и в 8.1 можно
|
|||
17
Necessitudo
14.10.14
✎
15:45
|
(15) Конечно - особенно если сам наложишь тот уровень блокировки который захочешь.
|
|||
18
ejikbeznojek
14.10.14
✎
15:45
|
У меня режим управления блокировками в конфигураторе стоит
"Автоматический". Насколько понял нужно будет поставить "Автоматический и управляемый" это может негативно сказаться на старом коде? |
|||
19
Ник второй
14.10.14
✎
15:46
|
1. Определить ресурс который блокируется, это можно быть вполне и не регистр и не константа. Определить можно например через ТЖ
2. Устранить проблему. |
|||
20
Ник второй
14.10.14
✎
15:46
|
(17) Вообще дурь.
|
|||
21
Ник второй
14.10.14
✎
15:46
|
(18) нет
|
|||
22
Ник второй
14.10.14
✎
15:47
|
(13) А какой смысл, если платформа позволяет штатно устанавливать различные уровни изоляции?
|
|||
23
Necessitudo
14.10.14
✎
15:48
|
(20) В смысле дурь? Ты отменил BEGIN { TRAN | TRANSACTION } ?
|
|||
24
Ник второй
14.10.14
✎
15:49
|
(23) Дурь в прямом смысле, так как "Платформа позволяет штатно устанавливать различные уровни изоляции"
|
|||
25
Necessitudo
14.10.14
✎
15:50
|
(24) Платформа использует далеко не все уровни транзакции, которые предоставляет SQL сервер.
|
|||
26
Ник второй
14.10.14
✎
15:51
|
(25) ну и какие в данном случае помогут, которые не использует платформа?
|
|||
27
Necessitudo
14.10.14
✎
15:53
|
(26) Snapshot
|
|||
28
Ник второй
14.10.14
✎
15:54
|
(27) И зачем тут он, если у нас только запись? 0_о
|
|||
29
Necessitudo
14.10.14
✎
15:55
|
(28) Всего лишь запись, какие мелочи)))
|
|||
30
Ник второй
14.10.14
✎
15:55
|
(28) + и между прочем Snapshot 1С-ка штатно использует, но реально тут он ни к чему.
|
|||
31
Necessitudo
14.10.14
✎
15:55
|
(30) Не ври, не использует.
|
|||
32
Ник второй
14.10.14
✎
15:56
|
(31) Использует.... естественно не 8.1
|
|||
33
Necessitudo
14.10.14
✎
15:57
|
(32) Я сказал Snapshot, а не Read Commited Snapshot.
|
|||
34
Ник второй
14.10.14
✎
16:00
|
(33) Вот как раз Snapshot без Read Commited Snapshot может иметь больше проблем, так как позволяет устанавливать общую блокировку ресурса.
Но если вернуться к задаче, то автору нужно грамотно изменить архитектуру регистров и возможно перевести на упр блокировки. |
|||
35
H A D G E H O G s
14.10.14
✎
16:01
|
А можно спросить - нафига вообще этот огород?
|
|||
36
Necessitudo
14.10.14
✎
16:01
|
(35) Письками помериться)
|
|||
37
Ник второй
14.10.14
✎
16:02
|
(35) +100500
|
|||
38
H A D G E H O G s
14.10.14
✎
16:03
|
Чтобы пользователь сам каждый раз не жал повторно кнопку, а тупо смотрел в застывшую 1С или пошел пить кофе?
|
|||
39
Ник второй
14.10.14
✎
16:28
|
(38) 20 секунд это долго, и то можно поменять.
А лучше всего изменить архитектуру, что бы блокировок в принципе не было. |
|||
40
MrStomak
14.10.14
✎
16:43
|
(29) Тебе объясняют, что в операциях записи в один ресурс две транзакции всегда несовместимы друг с другом, какой уровень изоляции ни поставь. В MSSQL проблема потерянного обновления решается даже в хинте WITH NOLOCK.
|
|||
41
MM
14.10.14
✎
17:08
|
(0) А почему в запросе на чтение нет ДЛЯ ИЗМЕНЕНИЯ ?
Для автоматического режима блокировок это обязательно. |
|||
42
Fragster
гуру
14.10.14
✎
17:12
|
в (0) имеено ВЗАИМОблокировки или таймауты?
|
|||
43
Fragster
гуру
14.10.14
✎
17:12
|
*именно
|
|||
44
ejikbeznojek
14.10.14
✎
17:39
|
Взаимоблокировки
{Документ.ЛистНабора(101)}: Ошибка при вызове метода контекста (Выполнить): Ошибка выполнения запроса "Конфликт блокировок при выполнении транзакции: Microsoft OLE DB Provider for SQL Server: Транзакция (идентификатор процесса 63) вызвала взаимоблокировку ресурсов блокировка с другим процессом и стала жертвой взаимоблокировки. Запустите транзакцию повторно. HRESULT=80004005, SQLSrvr: Error state=12, Severity=D, native=1205, line=1 " Выборка = Запрос.Выполнить().Выбрать(); |
|||
45
MM
14.10.14
✎
17:45
|
(44) Конструкция ДЛЯ ИЗМЕНЕНИЯ в языке запросов, как раз и служит для борьбы с взаимоблокировками в автоматическом режиме.
|
|||
46
Fragster
гуру
14.10.14
✎
19:26
|
зачем там вообще чтение из РС?
|
|||
47
hhhh
14.10.14
✎
19:37
|
(44) вот это полный бред:
ВЫБРАТЬ | Константы.ЗначениеРеквизита как знач |ИЗ | РегистрСведений.Константы КАК Константы |ГДЕ | Константы.ИмяКонстанты = &ИмяКонстанты"; как можно было регистр назвать "Константы"? Вы - самоубийца. |
|||
48
hhhh
14.10.14
✎
19:42
|
(47) и потом
Функция ПолучитьКонстантуБлокировкиИнформацииШКЛН() возвращает Возврат результат.Получить(0).знач; например Результат имеет 99 строчек, вам надо взять последнюю, 99-ю, а вы берете самую первую строку: результат.Получить(0) ??????? |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |