|
v8: Транзакция, исключение, запись документа. | ☑ | ||
---|---|---|---|---|
0
Тим
01.12.11
✎
12:37
|
Мое почтение сведующим!
Любезные, пробую реализовать следующую логику: в цикле создаются и сохраняются документы. В зависимости от заданных пользователем параметров для документов может вызываться проведение, при этом возможно два варианта поведения - при возникновении исключения откатить транзакцию, т.е. создание документа вообще, или просто оставить документ записанным, но непроведенным. Структура логики такова: Цикл НачатьТранзакцию Попытка ... Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); Если РежимПроводитьДокументы Тогда Попытка Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Исключение Если РежимОткатПриОшибкеПроведения Тогда ВызватьИсключение; КонецЕсли; КонецПопытки КонецЕсли ... ЗафиксироватьТранзакцию Исключение ОтменитьТранзакцию КонецПопыткиКонецЦикла однако при вызове процедуры с условием продолжения обработки в случае ошибки проведения документа при возникновении ошибки проведения цикл обработки продолжается, но транзакции отменены, документы не записаны. Вот и пытаюсь найти свою глупость... |
|||
1
catena
01.12.11
✎
12:40
|
Попытка
Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Исключение Если РежимОткатПриОшибкеПроведения Тогда ВызватьИсключение; КонецЕсли; КонецПопытки Вызвать исключение в исключении? Зачем, оно уже там. |
|||
2
Тим
01.12.11
✎
12:44
|
(1)
Каскад исключений нужен, чтобы "проглотить" отказ при попытке проведения. Внешней блок попытки, очевидно, просто отменит транзакцию. Мне же нужно сохранить непроведенный документ. |
|||
3
Murzz
01.12.11
✎
12:49
|
Может, так?
Попытка Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Исключение Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); |
|||
4
Maxus43
01.12.11
✎
12:51
|
если в транзакции будет 2 и больше исключения по попытке - вывалит ошибку и откатит всё
|
|||
5
Тим
01.12.11
✎
12:55
|
(3) может, и так, но всё же логика такова, что запись обязательна,
а вот проведение - опционально. Ну и, во-вторых, всё равно хочется понять - почему даже поглощенное исключение всё же откатывает транзакцию. (4) - пытаюсь найти явное описание такого поведения в доках, но пока не вижу. Впрочем, у меня сейчас под рукой только хэлп платформы. |
|||
6
catena
01.12.11
✎
12:56
|
Если я правильно поняла, то надо не ВызватьИсключение, а ОтменитьТранзакцию...
|
|||
7
Maxus43
01.12.11
✎
12:56
|
в явной транзакции с попытками внутри ошибка - "В этой транзакции уже происхродили ошибки" обычное поведение платформы
|
|||
8
Maxus43
01.12.11
✎
12:59
|
зачем в транзакции кстати? может просто запись/проведение доков в попытке и вести лог непроведённых. с чем связано желание обязательно првести/записать всю пачку?
|
|||
9
Тим
01.12.11
✎
12:59
|
(6) нет. мне не нужно отменять транзакцию - документ должен быть сохранен. А то, что его попытка проведения неудачна - пропустить.
|
|||
10
Тим
01.12.11
✎
13:02
|
(4) кста, у меня вроде бы только одно исключение возникает, при
попытке проведения. Во внешнем блоке исклюения не возникают. Однако же - отменена. |
|||
11
Тим
01.12.11
✎
13:04
|
(8) для меня это внешняя вводная заказчика,но есть там какая-то своя
логика - иногда нужно загружать доки вообще без попытки проведения (т. е. так и сказано - даже и не пытаться :, видимо, ещё какие-то неведомые движения происходят), а иногда - пробовать, и либо сохранять доки, либо вообще делать вид, что "ничего не было" |
|||
12
Maxus43
01.12.11
✎
13:04
|
(10) я имел ввиду что код вобще аварийно завершиться с ошибкой (7).
|
|||
13
Maxus43
01.12.11
✎
13:05
|
(11) сохраняй все доки в транзакции а потом уже по ним пробегай и проводи, сохраняться то все
|
|||
14
AAlexandra
01.12.11
✎
13:06
|
Может как-то так:
Попытка НачатьТранзакцию(); ... Если РежимПроводитьДокументы Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Иначе Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение Если РежимОткатПриОшибкеПроведения Тогда ОтменитьТранзакцию(); Иначе Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); ЗафиксироватьТранзакцию(); КонецЕсли КонецПопытки И все это (весь цикл) упаковать еще в одну транзакцию, чтобы записать все целиком, а не по документно.. |
|||
15
catena
01.12.11
✎
13:06
|
Может так проще?:
Попытка Если проводить тогда Провести Иначе ВызватьИсключение; КонецЕсли; Исключение Попытка Записать Исключение КонецПопытки КонецПопытки |
|||
16
Тим
01.12.11
✎
13:08
|
(13) Maxus43, в том и штука - иногда нужно сделать вид,
что ничего вообще не было. Пользователь решает - если выбрал вообще откат при непроведении, то документов (да и создаваемых попутно элементов нескольких справочников) в БД остаться не должно. |
|||
17
Maxus43
01.12.11
✎
13:08
|
имхо исключение тянет за собой откат транзакции
|
|||
18
Тим
01.12.11
✎
13:09
|
(14) - э, нет. Транзакция не на весь пакет вообще - это было сразу
определено. |
|||
19
Maxus43
01.12.11
✎
13:09
|
Если СделатьВид то
проводим в транзакции и если чо откатываем Иначе (13) Конец |
|||
20
Maxus43
01.12.11
✎
13:10
|
разбей на куски алгоритм, не пытайся всё предусмотреть в одной транзакции раз поведение разное. больше кода - не преступление
|
|||
21
catena
01.12.11
✎
13:10
|
"нет. мне не нужно отменять транзакцию - документ должен быть сохранен. А то, что его попытка проведения неудачна - пропустить"
Я не поняла, а что тогда откатывать при проведении? Если просто ПЫТАТЬСЯ провести и при этом всегда СОХРАНЯТЬ, то не надо вообще ничего вызывать, просто проведение в попытке. |
|||
22
AAlexandra
01.12.11
✎
13:13
|
Чет я подумала.. а зачем вообще транзакции при такой постановке задачи?
В (15) правильная мысль.. Попытка ... Если РежимПроводитьДокументы Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Иначе Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); КонецЕсли; Исключение Если НЕ РежимОткатПриОшибкеПроведения Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); КонецЕсли КонецПопытки |
|||
23
Тим
01.12.11
✎
13:14
|
(21) ещё раз уточню - если проведение неудачное, то по установке пользователя нужно либо сохранить все созданные сущности (сам док,
сопутсвующие ему элементы справочников), либо отктатить всё это. Пойми, речь не только о документе, но и о создании сопутствующих данных. |
|||
24
catena
01.12.11
✎
13:16
|
(23)Ну тогда в приведенном куске следует "ВызватьИсключение" заменить на "ОтменитьТранзакцию".
|
|||
25
hhhh
01.12.11
✎
13:19
|
(23) ну по-любому транзакция тебе не нужна, потому что проведение - это и есть транзакция, а запись тебе надо чтобы не входила в транзакцию.
|
|||
26
Sammo
01.12.11
✎
13:21
|
(23)
ЕстьОшибки = Ложь; НачатьТранзакцию Док.Записать(РежимсЗаписиДокумента.Запись); Попытка Док.Записать(РежимсЗаписиДокумента.Проведение); Исключение ЕстьОшибки = Истина; КонецПопытик Если ЕстьОшибки и НастройкаПользователяОткатитьПриНеудаче Тогда ОтменитьТранзакцию(); Иначе ЗачикфироватьТранзакцию(); КонецЕсли; |
|||
27
Maxus43
01.12.11
✎
13:22
|
(26) 2 неудачных проведения приведут к программной ошибке
|
|||
28
Тим
01.12.11
✎
13:22
|
(22) ну как минимум такая реакция неверна - что там док записывать, если причиной исключения стала не ошибка проведения, а, скажем,
ошибка предварительного создания элемента какого-либо справочника? И это никак не зависит от РежимОткатПриОшибкеПроведения, мне незачем сохранять кривой док. |
|||
29
Тим
01.12.11
✎
13:23
|
(25) - прости, но думаю, что Ты поторопился с советом :)
|
|||
30
Тим
01.12.11
✎
13:24
|
(26) угу, сейчас попробую отказаться от каскада попыток и действовать
через флаг в общем блоке обработки исключения. |
|||
31
Тим
01.12.11
✎
13:27
|
Но всё равно академическое любопытсво не отпускает - в терминах
программы всё вроде верно, но на деле исключение не поглощается, и транзакция откатывается. Кстати, это происходит в обход явного вызова ОтменитьТранзакцию, перехода в обработчик не происходит. где-то в тёмных, жутких лабиринтах платформы... |
|||
32
AAlexandra
01.12.11
✎
13:30
|
(25) Не, транзакции ему все-таки нужны.
Потому что если документ не провелся - ему надо не только документ не записывать, но и все созданные вместе с документом объекты удалить.. Попытка ОшибкаПриЗаписиПроведенииДокумента = ложь; НачатьТранзакцию(); ... <создание всех подчиненных объектов> ... ОшибкаПриЗаписиПроведенииДокумента = Истина; Если РежимПроводитьДокументы Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Иначе Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение Если ОшибкаПриЗаписиПроведенииДокумента и (НЕ РежимОткатПриОшибкеПроведения) Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); ЗафиксироватьТранзакцию(); Иначе ОтменитьТранзакцию(); КонецЕсли; КонецПопытки; |
|||
33
Тим
01.12.11
✎
13:31
|
(32) именно, флаг таки необходим. Пробую, сообщу.
|
|||
34
hhhh
01.12.11
✎
13:42
|
(32) ну вот смотри: в (9) он пишет, что документ нужно записывать. А если Документ он записывает, то как он сможет удалить связанные с ним объекты? Поэтому транзакция не нужна. В обработке проведения используется своя транзакция. А флаги он может спокойно проставить при помощи попытки-исключения.
|
|||
35
Тим
01.12.11
✎
13:43
|
(34) - "А если Документ он записывает, то как он сможет удалить связанные с ним объекты?"
Вот именно через отмену транзакции, индид! |
|||
36
catena
01.12.11
✎
13:58
|
(31)
Цикл НачатьТранзакцию Попытка ... Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); Если РежимПроводитьДокументы Тогда Попытка Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Исключение Если РежимОткатПриОшибкеПроведения Тогда ВызватьИсключение; //ВОТ ЭТО ИСКЛЮЧЕНИЕ ВЫВОДИТ ИЗ ВНЕШНЕЙ ПОПЫТКИ, ПОТОМУ ЧТО ВНУТРЕННЯЯ САМА ИСКЛЮЧИЛАСЬ КонецЕсли; КонецПопытки КонецЕсли ... ЗафиксироватьТранзакцию Исключение ОтменитьТранзакцию КонецПопыткиКонецЦикла |
|||
37
Maxus43
01.12.11
✎
13:59
|
кто проверял вобще ваши построения? транзакция да вложеные попытки... сделайте там в попытках несколько ошибок и узрите
|
|||
38
Тим
01.12.11
✎
15:24
|
(36) РежимОткатПриОшибкеПроведения = ложь. А откат всё-таки происходит.
|
|||
39
AAlexandra
01.12.11
✎
15:47
|
(38) Запись связанных объектов и проведение документа надо разнести по разным транзакциям, потому что в противном случае ошибка при проведении документа отменит всю транзакцию со связанными обектами.
Попытка ОшибкаПриЗаписиПроведенииДокумента = ложь; НачатьТранзакцию(); ... <создание всех подчиненных объектов> ... Если (НЕ РежимОткатПриОшибкеПроведения) Тогда ЗафиксироватьТранзакцию(); НачатьТранзакцию(); КонецЕсли; ОшибкаПриЗаписиПроведенииДокумента = Истина; Если РежимПроводитьДокументы Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Проведение); Иначе Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение Если ОшибкаПриЗаписиПроведенииДокумента и (НЕ РежимОткатПриОшибкеПроведения) Тогда Док.ЗаписатьДокумент(РежимЗаписиДокумента.Запись); ЗафиксироватьТранзакцию(); Иначе ОтменитьТранзакцию(); КонецЕсли; КонецПопытки; |
|||
40
Тим
02.12.11
✎
02:48
|
Пока могу констатировать по трассировке MS SQL - при вызове НачатьТранзакцию по-честному имею BEGIN TRAN, записываю док, потом пытаюсь провести, "проглатываю" исключение, но когда
дохожу до Зафиксировать - получаю в трассе явный ROLLBACK. Зэц ол фолкс. Грустно. И исключения не возникает, и зафиксировать вызывает, и при этом транзакция отменена. |
|||
41
rs_trade
02.12.11
✎
03:22
|
при исключении при проведении взводи флажек, выходи из транзакции и записывай документ в другой транзакции. не морочтесь с вложениями.
|
|||
42
Amiralnar
02.12.11
✎
04:35
|
Скажите, вы не помните, в документации описано поведение транзакций 1С?
Например, что вложенная транзакция - это виртуальная транзакция, активной (настоящей) является только исходная. И про то, что исключение в транзакции приводит к её откату безусловно? Ну например, перехватили вы исключение - и что? Исключение случилось, и транзакция больше не валидна. А поскольку она одна на всю операцию - в конце будет ROLLBACK/ |
|||
43
Тим
02.12.11
✎
09:12
|
(42) я не забыл - я не знал. Мой стаж работы активной работы с платформой 1С -
немного более 3-х месяцев. В (5) я написал, что честно пытался найти описание во встроенной документации платформы, но не нашел. Я, разумеется, проштудировал сеть на эту тему, нашел достаточно подтверждений обсуждаемого факта, и упоминание существования статьи по данной теме в ресурсах ИТС. В инете я её не нашел, сегодня получу диск ИТС, и, надеюсь, увижу официальное признание именно такого поведения. |
|||
44
Тим
02.12.11
✎
09:20
|
А, да - самое главное. Я многое готов принять и простить, но вот такое поведение,
когда по логике кода происходит вход в штатную процедуру ЗафиксироватьТранзакцию, и её выполнение завершается откатом без какого-либо исключения, уведомления и проч, лишь скупой отпиской в системный журнал - такое поведение даже с натяжкой не могу признать фичей. Моё ничтожное мнение - баг. И я даже наберусь наглости отправить своё чириканье в саппорт 1С :) |
|||
45
Amiralnar
02.12.11
✎
10:56
|
(44) У вас стаж на форуме два года. Как случилось, что
> таж работы активной работы с платформой 1С - немного более 3-х месяцев ??? |
|||
46
Amiralnar
02.12.11
✎
10:58
|
(44) А как в вашем случае должна действовать платформа? Не забывайте - ей очень хочется сохранить целостность базы данных.
|
|||
47
Тим
02.12.11
✎
11:13
|
(45) раньше я поддерживал 1С в фоновом режиме, в побочной нагрузке.
(46) очевидно, как - система при вызове ЗафиксироватьТранзакцию должна сообщить в контекст вызова, что она транзакию не зафиксировала, а отменила. Вроде бы вполне естественное и реализуемое желание. Синтаксис: ЗафиксироватьТранзакцию() Описание: Завершает успешную транзакцию. Все изменения, внесенные в информационную базу в процессе транзакции, будут записаны. А оказалось, что не будут. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |