Имя: Пароль:
1C
 
исключение "грязного чтения" набора записей регистра сведений 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".
Ошибка? Это не ошибка, это системная функция.