|
исключение "грязного чтения" набора записей регистра сведений 1С | ☑ | ||
---|---|---|---|---|
0
МеталлКор
06.10.15
✎
09:47
|
Добрый день, уважаемые коллеги.
В системе на базе 8.2 предусмотрено два регл. задания: 1. Задание 1: помещает записи в регистр сведений, определенный рядом измерений (не подчинен регистратору, периодичность секунда), далее вторым шагом обрабатывает записи, заполняет некие реквизиты набора. При этом в начале и в конце обработки выставляется конструкции "НачатьТранзакцию", "ЗафисироватьТРанзакцию". Возможна ситуация, когда требуется отменить запись некоторого набора, в связи с чем применяется метод "ОтменитьТранзакицю". 2. Задание 2: должно обратиться к регистру сведений, отобрать записи по определенному фильтру и далее внести изменения в его набор записей. Вопрос: задание 2 должно получить для обработки набор записей тот, который окончательно обработан заданием 1 после выполнения команды "ЗафиксироватьТРанзакцию". На текущий момент в задание 2 попадают записи, которые добавлены заданием 1, но не обозначены как "ЗафиксироватьТРанзакцию". Как лучше организовать поведение системы с целью исключения "грязного" чтения заданием 2? |
|||
1
МеталлКор
06.10.15
✎
09:49
|
Дополнительно: в свойствах конфигурации выставлен режим блокировки данных "Управляемый"
|
|||
2
Сергиус
06.10.15
✎
09:53
|
(0)БлокировкаДанных в 1-м задании.
|
|||
3
МеталлКор
06.10.15
✎
10:06
|
(2) Вот код:
БлокировкаДанных = Новый БлокировкаДанных; // Выбрать пространство блокировок РегистрНакопления.ОстаткиНоменклатуры, т.к. мы собираемся анализировать // остатки регистра ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСВедений.ТК_syn_customers"); ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; ЭлементБлокировки.УстановитьЗначение("id", Стр.id); ЭлементБлокировки.УстановитьЗначение("author", Стр.author); ЭлементБлокировки.УстановитьЗначение("created_at", Стр.created_at); БлокировкаДанных.Заблокировать(); НаборЗаписей = РегистрыСведений[ИмяТаблицы].СоздатьНаборЗаписей(); НаборЗаписей.Отбор.id.Установить(Стр.id); НаборЗаписей.Отбор.author.Установить(Стр.author); НаборЗаписей.Отбор.created_at.Установить(Стр.created_at) ; НаборЗаписей.Прочитать(); НаборЗаписей.Очистить(); НоваяЗапись = НаборЗаписей.Добавить(); ЗаполнитьЗначенияСвойств(НоваяЗапись, СТр); Если ЗначениеЗаполнено(Стр.synstatus) Тогда НоваяЗапись.Статус= Стр.synstatus; Иначе Если Не ЗначениеЗаполнено(Стр.synstatus) Тогда НоваяЗапись.Статус= "Изменен"; ИНаче НоваяЗапись.Статус= "Добавлен"; КонецЕсли; КонецЕсли; НаборЗаписей.Записать(Истина); БлокировкаДанных.РазблокироватьДанные(); Выставлю точку остановы на последней строке. Если я делаю селект регл. задания 2, получаю результат, куда включены записи НаборЗаписей. а они попадать не должны. |
|||
4
Гёдза
06.10.15
✎
10:09
|
чтение делать внутри транзакции
|
|||
5
Гёдза
06.10.15
✎
10:10
|
не заметил в коде транзакции. А без транзакции блокировка ничего не делает
|
|||
6
МеталлКор
06.10.15
✎
15:41
|
(4) (5) она есть, просто забыл указать. перед вызовом это процедуры идет "НачатьТранзакцию" из другого модуля. Аналогично после выполнения процедуры "ЗафиксироватьТранзакцию"
НачатьТранзакцию(); МояПроцедураОБработкиЗаписей(); ЗафиксироватьТРанзакцию(); |
|||
7
Cyberhawk
06.10.15
✎
15:43
|
А ты в коде перед установкой блокировки проверь "ТранзакцияАктивна()" и нам сообщи
|
|||
8
Cyberhawk
06.10.15
✎
15:43
|
И неясно, зачем вот это:
НаборЗаписей.Прочитать(); НаборЗаписей.Очистить(); |
|||
9
kihor
06.10.15
✎
15:45
|
Согласен с (4). Чтение вне транзакции 1С - грязное. Если сделать НачатьТранзакцию() в задании №2, а затем делать чтение, то будет другой, более высокий, уровень изоляции.
|
|||
10
МеталлКор
06.10.15
✎
16:10
|
(7) так и есть, дает истину. (9) сделал так:
НачатьТранзакцию() МояПроцедураОБработкиЗаписей(); //тут идет блокировка ЗафиксироватьТранзакцию(); В регл. задании 2 сделал так: НачатьТранзакцию(); Запрос = Новый Запрос(); Запрос.Текст = "ВЫБРАТЬ | ТК_syn_customers.id |ИЗ | РегистрСведений.ТК_syn_customers КАК ТК_syn_customers |ГДЕ | ТК_syn_customers.id = &id" ; Запрос.УстановитьПараметр("id", "'BEB4BC37-308D-11DE-BCB9-00119525EDE5'"); ВЫборка = Запрос.Выполнить().Выбрать(); Сообщить(ВЫборка.Количество()); ЗафиксироватьТранзакцию(); На выходе получил ошибку: Конфликт блокировок при выполнении транзакции: Microsoft OLE DB Provider for SQL Server: Превышено время ожидания запроса на блокировку. HRESULT=80040E31, SQLSrvr: SQLSTATE=HYT00, state=33, Severity=10, native=1222, line=1 Но меня интересует результат с пустым значением, то есть, обработка должна пройти и результат поиска должен дать 0 |
|||
11
kihor
06.10.15
✎
16:23
|
(10) Время ожидания превышено, когда вы ставите точку останова в первом задании? Если у вас первая обработка ставит исключительную блокировку при попытке записать запись в регистр, то вторая обработка будет заблокирована при попытке прочитать эту запись, если не использовать грязное чтение. У вас это и происходит. Если первая обработка заканчивается быстро, то вторая обработка ждет окончания транзакции и продолжает чтение записи. Кстати, какой у вас режим работы 1С (файловый или клиент-серверный) и какая БД?
|
|||
12
МеталлКор
06.10.15
✎
16:31
|
(11) мне необходимо, что бы второе задание отработало безаварийно и дало пустой результат, так как транзакция первого регл. задания не зафиксирована до конца. Это вообще реализуемо?
У меня клиент-серверный вариант. |
|||
13
kihor
06.10.15
✎
16:44
|
(12) Если БД "блокировочник", как MSSQL, то не реализуемо, т.к. в MSSQL писатели блокируют читателей. В "версионниках" типа ORACLE - это реализуемо, т.к. там писатели не блокируют читателей. Но я не помню, как 1С себя ведет в случае ORACLE. Там по моему при автоматическом режиме блокируется вся таблица, но я не уверен.
P.S. На всякий случай уточню, что я не утверждаю, что ORACLE лучше MSSQL. Просто они по разному подходят к этому вопросу. |
|||
14
ptiz
06.10.15
✎
16:49
|
(3) Должно работать
Но что за метод "РазблокироватьДанные()"? Не вижу такого в СП. |
|||
15
МеталлКор
06.10.15
✎
16:52
|
(14) это опечатка. данная команда не работает.
|
|||
16
ptiz
06.10.15
✎
16:57
|
(12) "что бы второе задание отработало безаварийно и дало пустой результат" - а вот так уже не выйдет.
Единственный способ - сначала записать пустой набор, потом его восстановить. |
|||
17
ptiz
06.10.15
✎
16:57
|
При этом не использовать блокировки
|
|||
18
Cyberhawk
06.10.15
✎
17:44
|
Автор, попробуй во втором регл. задании не запросом, а созданием набора записей с установкой отбора и чтением проверить кол-во записей в получившемся наборе
|
|||
19
Casey1984
06.10.15
✎
17:50
|
Разнести рег задания по графику?
|
|||
20
Casey1984
06.10.15
✎
17:51
|
Придумать признак "МОЖНО ЧИТАТЬ"?
|
|||
21
Casey1984
06.10.15
✎
17:52
|
И да, я не спец в блокировках, разве нельзя увидеть заблокирован ли объект/набор записей?
|
|||
22
Casey1984
06.10.15
✎
17:56
|
Можно еще блокировать с отбором по измерению, разве нет? первое пишет с отбором "измерение = 1", второе читает с отбором "измерение = 2", потом меняемся.
|
|||
23
Casey1984
06.10.15
✎
17:57
|
Я все сказал. ;)
|
|||
24
and2
06.10.15
✎
17:58
|
(0) вообще то в таких случаях задания объединяют в пул с последовательным выполнением.
|
|||
25
Neo111
06.10.15
✎
18:12
|
(12) Чтобы дало пустой результат, делать примерно как сказано в (20), т.е. до начала первой транзакции ставить какой-то признак, после установки которого вторая транзакция эти данные уже не прочитает. Либо реализовывать с помощью блокировок, а чтобы уменьшить вероятность таймаута, разнести задания по времени.
|
|||
26
Сторно абсурда
06.10.15
✎
18:21
|
(12) помести Запрос.Выполнить().Выбрать(); второго задания в попытку исключение
а так, (24) + 1 |
|||
27
Casey1984
06.10.15
✎
18:26
|
(24) Действительно, нафиг их разделять?
|
|||
28
Serginio1
06.10.15
✎
18:26
|
||||
29
Гёдза
06.10.15
✎
18:32
|
переходи на 8.3 без режима совместимости с 8.2 и упр блокировки
|
|||
30
Neo111
07.10.15
✎
08:40
|
(29) Если речь про уровень изоляции Read Comitted Snapsot, то в этом случае ТС будет получать последнюю зафиксированную версию данных, а не пустой результат.
|
|||
31
bootini
07.10.15
✎
10:23
|
(0) Добавь в регистр измерение, например "номер сообщения" или булево "Обработано" , первое задание обрабатывает записи с номером сообщения "1", после обработки записей изменяет номер сообщения на "2", второе задание обрабатывает записи только с номером сообщение "2".
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |