Имя: Пароль:
1C
1С v8
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) очевидно, как - система при вызове ЗафиксироватьТранзакцию должна
сообщить в контекст вызова, что она транзакию не зафиксировала,
а отменила. Вроде бы вполне естественное и реализуемое желание.

Синтаксис:
ЗафиксироватьТранзакцию()
Описание:
Завершает успешную транзакцию. Все изменения, внесенные в информационную базу в процессе транзакции, будут записаны.

А оказалось, что не будут.