Имя: Пароль:
1C
1С v8
Как правильно разруливать такие ситуации (грязное чтение)
, ,
0 degot
 
04.11.14
12:38
Предположим есть такая ситуация : есть какие-то документы, которые проводятся длительное время. И есть процесс , в котором делаются запросы к таблице данного вида документов. Результат запроса обрабатывается, создаются объекты базы данных со ссылкой на на те самые документы.
Но бывают ситуации когда документ в итоге не проведется, в итоге объекты   получаются с битыми ссылками на документы . В общем как правильно обрабатывать такие ситуации? Как исключить из запроса доки, по которым транзакция не завершена? Спасибо

платформа 8.2, управляемый режим блокировок, sql 2012
1 Bober
 
04.11.14
12:41
(0) перед выполнение запроса НачатьТранзакцию(), после выполнения ОтменитьТранзакцию().
2 Armando
 
04.11.14
12:49
3 Armando
 
04.11.14
12:58
Можно перед тем как выполнится это "создаются объекты базы данных со ссылкой на на те самые документы." накладывать исключительную блокировку на документ. Если не заблокировалось, значит с документом что-то происходит.
4 herfis
 
04.11.14
13:20
(0) Если именно "исключить из запроса доки, по которым транзакция не завершена", тогда (1) - чтение в транзакции READ COMMITTED, а не "грязное".
5 Armando
 
04.11.14
13:23
Кстати на 8.3 эту проблему вроде решили
6 AlexITGround
 
04.11.14
13:25
(4) мсье, не ругайтесь такими словами, ТС-а может спугнуть такой внезапный тон
7 floody
 
04.11.14
14:06
(1) прав, в 1С грязное чтение только вне транзакции. все, что в транзакции (явной или неявной) - это уже минимум read committed
8 floody
 
04.11.14
14:08
(0) если у вас какой-то документ проводится - это значит что он уже записан

причем тут битые ссылки? битые образуются, если документ удалить без контроля ссылочной целостности
9 Armando
 
04.11.14
14:11
(8) Может там при проведении Отказ = Истина
10 Web00001
 
04.11.14
14:29
(9)дык это же все равно, документ то есть, а проведен он или нет, это дело уже 10е.
11 Armando
 
04.11.14
14:35
(10) Создай новый документ, в при записи или обработке проведения сделай отказ, и попробуй провести его. Он у тебя не проведется и не запишется. Ну то есть в момент проведения ссыль будет, отказ заставит откатить транзакцию, и ссылки не станет.
12 vi0
 
04.11.14
15:05
(0) расскажи что за задачу решаешь
зачем "исключить из запроса доки, по которым транзакция не завершена"?
ты их потом будешь отдельно обрабатывать? эти документы по которым транзакция уже будет завершена
13 floody
 
04.11.14
15:17
(11) это верно в том случае, если вы создали документ и записываете его программно с режимом "проведение"

в конфигурациях обычно у пользователя документ сначала записывается, потом уже проводится
14 Armando
 
04.11.14
15:21
(13) "конфигурациях обычно у пользователя документ сначала записывается, потом уже проводится"
проверить не желаешь?
15 herfis
 
04.11.14
16:05
(13) Чушь какая-то. Проведение на 8-ке всегда было частью транзакции записи. Или появились быдло-типовые, где проведение нового документа разбито на две транзакции?
16 degot
 
04.11.14
16:34
(12) да, они обработаются следующим заходом
17 Обработка
 
04.11.14
16:39
(0)
В запросе у вас должно быть проверка "ссылка.проведен".
Если документ записан но не проведен тогда не попадет в ваш запрос. А если уж поапл тогда значит документ уже провелся.
Если документ перепроводится эо уже другой случай.
18 Зеленый пень
 
04.11.14
16:51
(0) "Результат запроса обрабатывается, создаются объекты базы данных со ссылкой на на те самые документы." - в этот момент накладывать блокировку на документы из запроса, если удалось - всё ок.
19 vi0
 
04.11.14
17:02
(18) не, если ТС говорит про битые ссылки на документы, значит достаточно запрос делать в транзации - запрос не увидит эти документы т.к. чтение не будет грязным
20 tridog
 
04.11.14
18:10
(17) Если документ проведен, но транзакция еще не зафиксирована - то при грязном чтении параллельный сеанс вполне себе прочитает незафиксированное состояние через условие вида "Ссылка.Проведен".

Ваш совет ничем не отличается от исходной ситуации в (0).

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

Как уже писали Выше - самый простой вариант - это выполнять чтение в транзакции, тем самым получив в СУБД уровень изоляции Read committed.

Вообще говоря, для современных конфигураций (управляемые блокировки, режим совместимости 8.3 и т.д.) - уже сложно найти причины, которые бы делали чтение вне транзакции обоснованным.
21 vi0
 
04.11.14
18:22
> выполнять чтение в транзакции, тем самым получив в СУБД уровень изоляции Read committed.
у него управляемые блокировки, поэтому до субд не дойдет

> уже сложно найти причины, которые бы делали чтение вне транзакции обоснованным.
отчеты, по прежнему, логично выполнять вне транзакции
22 tridog
 
04.11.14
18:44
(21) > у него управляемые блокировки, поэтому до субд не дойдет

Мы говорим про уровень изоляции при чтении. Чтение до СУБД дойдет в любом случае (вместе с уровнем изоляции). Управляемые блокировки этому не помешают.

> отчеты, по прежнему, логично выполнять вне транзакции

Ну они действительно так и формируются на текущей платформе.
А какие от этого плюсы?
23 vi0
 
04.11.14
19:22
(22) почему не помешают?

Про плюсы. Транзакции всегда ипользуют ресурсы и задействовать их есть смысл, когда будет реальная необходимость
24 Armando
 
04.11.14
19:40
Вот в тему про 8.3:
http://downloads.v8.1c.ru/content//Platform/8_3_5_1248/1cv8upd.htm#4cc794a4-7d56-11e1-b5d1-e61f135f174b
Как было:
Microsoft SQL Server 2005 и выше использовался в режиме блокировок. Использовался уровень изоляции транзакций READ_COMMITED. При чтении вне транзакций использовалось «грязное» чтение.

Как стало:
При работе с Microsoft SQL Server версии 2005 и выше, используется режим управления версиями строк, если конфигурация использует режим управляемых блокировок. Используется уровень изоляции транзакций READ_COMMITED_SNAPSHOT. При чтении данных вне транзакций используется согласованное чтение.

Реализованные изменения приводят:
К уменьшению блокировок и взаимоблокировок при выполнении запросов, работающих в транзакции;
Исчезновению ошибок при выполнении запросов вне транзакции над часто модифицируемыми прикладными объектами;
Получению согласованных результатов отчета вне транзакции на момент выполнения отчета.
25 tridog
 
04.11.14
19:45
(23) Потому что собственный менеджер блокировок внутри платформы не может влиять на то, как СУБД читает данные.
26 vi0
 
04.11.14
19:50
(25) я говорил, что упр блокировки работать будут и при чтении, и блокировки субд тут вторичны
27 tridog
 
04.11.14
20:06
(26) Мне кажется, что Вы несколько не до конца разобрались с тем, что такое управляемые блокировки.

Могу прокомментировать Ваше высказывание так:

1. При выполнении запросов управляемые блокировки сами по себе не устанавливаются. Вообще :) Чтобы бы устанавливались управляемые блокировки при чтении - нужно либо устанавливать их из встроенного языка (объект БлокировкаДанных), либо выполнять чтение не через запросы, а через объектную технику (РегистрСведенийМенеджерЗаписи и т.д.).

2. При чтении вне транзакции управляемые блокировки вообще не могут устанавливаться - можно проверить через объект БлокировкаДанных и техжурнал по событию TLOCK. Кстати в офф. документации (а не на "сленге") они называются транзакционными блокировками, а не управляемыми.

3. Использование управляемых блокировок не отменяет блокировок в СУБД, и неправильно считать, что блокировки СУБД вторичны. Например, даже при использовании управляемых блокировок реальны ситуации избыточных блокировок в СУБД - по-максимуму такие ситуации исключены в 8.3 без режима совместимости, как тут уже выше писали.

4. То, "прочитаются" ли запросом данные параллельных незафиксированных транзакций вообще никак не зависит от блокировок! Ни от блокировок в СУБД, ни тем более, от управляемых блокировок. А зависит только от уровня изоляции транзакций, которым мы можем управлять только неявно. Что автору и было посоветовано - в виде выполнения запроса в транзакции.
28 vi0
 
04.11.14
22:28
1. согласен
2. 3.  зачем вы это написали?
4. странный абзац с учетом того, что уровень изоляции как раз задает, как именно будут блокироваться данные
еще странно советовать автору рулить блокировками СУБД (уровнем изоляции) при том что конфигурация у него на управляемых
29 Ник второй
 
04.11.14
22:38
(27)
1. Ложь. Блокировки ставятся всегда
2. Привыполнении запроса ставится блокировка на чтении, смотри профайлер
4. мда, (28) в части 4 пункта +1
30 tridog
 
04.11.14
23:06
(28) Уровень изоляции задает не только стратегию блокировки данных при чтении. Еще, например, стратегию чтения данных, заблокированных другой транзакцией (несогласованное чтение).

> При том что конфигурация у него на управляемых

Управляемые блокировки в этом случае (выполнение запроса) вообще не устанавливаются. При чем тут они - непонятно.

При выполнении запроса вне транзакции допускается несогласованное чтение (до 8.3 без совместимости).

При выполнении запроса в транзакции в этом случае платформа использует READ_COMMITED - что ликвидирует грязное чтение.

Это и было посоветовано автору, притом сразу в первом ответе)

(29) Профайлер показывает блокировки СУБД. Речь шла про управляемые блокировки (это отдельно подчеркивалось).
31 Torquader
 
04.11.14
23:41
Начнём с того, что если мы открываем транзакцию и обращаемся к объекту, изменённому в другой ещё неподтверждённой транзакции, то будет блокировка и транзакция будет ожидать завершения транзакции проведения.
Однако, возможна ситуация, когда при проведении данные для записи в таблицы (например, регистры) готовятся, но ещё не были записаны - в этом случае - транзакция чтения получит старые данные, и ничего удивительного в этом нет.
32 vi0
 
05.11.14
07:57
(30) еще раз: зачем ему советовать инструменты субд, 8.3 и прочее, когда он написал, что у него 8.2 управляемые блокировки - для этого есть соответствующие инструменты
33 vi0
 
05.11.14
08:02
(29) всегда ставятся упр блокировки?
а можно пример кода?
34 tridog
 
05.11.14
08:16
(32) Инструменты СУБД ему никто не советовал. Ему посоветовали выполнять запрос в транзакции - изменив непосредственно код на встроенном языке.
Описание того, почему это изменит ситуацию я привел в ответ на совет добавить в запрос условие вида Ссылка.Проведен.

Соответствующие инструменты для того, чтобы избежать грязного чтения на 8.2 (хоть на управляемых блокировках, хоть на автоматических) - это выполнять чтение в транзакции.
Само по себе использование управляемых блокировок не отменяет грязного чтения.

Попутно много раз было отмечено (не только мной), что на 8.3+ проблемы вообше нет в принципе из-за изменений в платформе (всегда считал, что это полезная информация).
35 herfis
 
05.11.14
10:30
(34) "на 8.3+ проблемы вообше нет в принципе из-за изменений в платформе"
Не совсем так.
Проблема не в платформе, а логике работы используемой СУБД. В версионниках этой проблемы и не было никогда. В postgres, например. Просто 8.3+ научилась работать с MSSQL в режиме версионника, который там с некоторых пор появился (см. 24)
Как дела обстоят в DB2 точно не знаю, но вроде как он остался чистым блокировочником а значит и грязное чтение вне транзакций в 1С там осталось скорее всего.
36 degot
 
05.11.14
11:03
(35) а вы случаем не в курсе, будет ли 8.3 работать  с версиями, если конфа в режиме совместимости?
37 herfis
 
05.11.14
12:13
(36) Не в курсе.