Сколько операций рекомендуется выполнять в рамках одной транзакции?

Автор Тема: Сколько операций рекомендуется выполнять в рамках одной транзакции?  (Прочитано 2894 раз)

0 Пользователей и 12 Гостей просматривают эту тему.

Оффлайн Андрей НикифоровАвтор темы

  • ADN OPEN
  • Сообщений: 13
  • Карма: 2
  • Энтузиаст-одиночка
Добрый день, коллеги!

Теоретический вопрос, прошу прояснить ситуацию - если кто может дать ссылку или сам проводил эксперименты на эту тему.
Вопрос такой: какова лучшая практика в использовании транзакции - сколько операций рекомендуется проводить в рамках одной транзакции, как лучше поступать - все запихивать в одну транзакцию, или последовательно открывать/закрывать несколько транзакций, в рамках каждой из них выполняя однотипные операции.

В качестве примера могу привести вот такую задачу: мне нужно в активном чертеже на каждом листе (Layout) создать область печати, соответствующую по размерам объекта (Entity), который находится на этом листе, если его внешняя геометрия (GeometricExtents) соответствует размерам стандартных форматов листов (А4, А3 и т.д.)
Что я делаю:
1. Читаю словарь листов, получаю указатели на все листы, перебираю их, открываю каждый лист на чтение и получаю их свойства.
2. Перебираю все объекты чертежа, открываю их на чтение, и если их геометрия соответствует требованиям, для каждого листа  сохраняю координаты будущей области печати.
3. Снова перебираю все листы, на этот раз открываю их на запись, и устанавливаю область печати по заранее вычисленным координатам.

При таком раскладе, я могу:
1. Открыть одну транзакцию и все три операции сделать в ее рамках.
2. Для каждой группы операций открывать/закрывать свою транзакцию, т.о. у меня будет три последовательных транзакции.
3. Открыть/закрыть транзакцию для первой операции, для второй операции - открывать/закрывать отдельную транзакцию для обработки объектов на каждом листе (т.е. транзакций будет столько, сколько листов в чертеже), и для третьей операции открыть/закрыть отдельную транзакцию.

Вопрос - как лучше делать, знаю, что можно сделать и так и так, но каковы рекомендации Autodesk по данному вопросу?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 828
  • Карма: 168
    • Мои плагины к Автокаду
Про такие рекомендации я не слышал. Практически имеет смысл делать в одной транзакции большие быстрые циклы. Открытие транзакции не очень много времени съедает и в отдельных "одноразовых" процедурах вполне может быть своя транзакция. Так методы красивей получаются и будет удобнее передавать список безопасных ObjectId, а не опасные DBObject. Но есть конечно нюансы.
Замечено нестабильное поведение Автокад на работе с тысячами BRep солидов (фаталит). Вроде бы чутка по стабильней получается, если разбить транзакцию на части, по несколько сотен солидов. Но это из области танцев с бубном.  Вот если на отдельные команды бить, то точно заметно меньше фаталов.
Многие действия (в том числе работу с менеджером листов) требуется делать СТРОГО при закрытых всех транзакциях. Так что хочешь, не хочешь, а начинается свистопляска с кучей отдельных транзакций.
Для вашего примера не вижу разницы. Оформляйте так, чтоб был чище код.


Оффлайн Андрей НикифоровАвтор темы

  • ADN OPEN
  • Сообщений: 13
  • Карма: 2
  • Энтузиаст-одиночка
Спасибо за мнение. Уже становится яснее. Например, если
передавать список безопасных ObjectId, а не опасные DBObject
то ясно, что метод, куда передаем идентификаторы, должен открывать собственную транзакцию (то есть к этому времени все открытые транзакции были закрыты). Или нет? Можно же методу и открытыю транзакцию передать, вместе с ObjectId? Насколько тогда будет "опасной" такая техника?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 828
  • Карма: 168
    • Мои плагины к Автокаду
Я когда-то в коротких "быстрых" функциях пытался использовать TopTransaction. Но при поиске глюков в обработчиках событий, я вообще не понимают - что это за транзакция? Моя или Автокад создал? Когда будет закрыта? И будет ли, или почему-нибудь будет откат? Когда я понял, что никак это все не контролирую, я переписал весь код и теперь передаю МОЮ транзакцию во все методы. Она бывает нужна даже если на входе DBObject. И еще рабочую базу данных часто передаю - с ней тоже много нюансов. Если напрягают методы с большим количеством аргументов, то можно класс-менеджер написать, который хранит транзакцию и базу данных.
« Последнее редактирование: 06-01-2025, 11:18:01 от avc »

Оффлайн Андрей НикифоровАвтор темы

  • ADN OPEN
  • Сообщений: 13
  • Карма: 2
  • Энтузиаст-одиночка
теперь передаю МОЮ транзакцию во все методы
Да, я тоже почти всегда так делаю. В том числе и поэтому возник вопрос, который я задаю в теме - правильно ли таскать одну транзакцию из метода в метод, или лучше открывать в каждом методе свою для небольшой порции операций. И вообще - сколько операций может "вместить" одна транзакция. Я так понимаю, четкого ответа нет, каждый делает, как умеет...

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 828
  • Карма: 168
    • Мои плагины к Автокаду
Совершенно точно, что нет ограничений на количество объектов в одной транзакции. Я спокойно пробегаюсь в одной транзакции по всей модели в огромных чертежах - ни проблем, ни дополнительных томозов. Комит транзакции похоже вообще ничего не делает (это совсем не те транзакции, что в нормальных базах данных). А откат конечно будет долгим, если очень много редактировать в одной транзакции. Но никаких проблем, связанных именно с количеством объектов или количеством изменений я лично не замечал. Интересно, конечно, что скажут эксперты..

Оффлайн alz

  • ADN OPEN
  • ***
  • Сообщений: 108
  • Карма: 12
Комит транзакции похоже вообще ничего не делает
Вот с этим не согласен, есть у меня одна прога, которая рекурсивно по блокам проходится кое что меняет и другие действия, на чертеже в 60 метров она пыхтела минут 10-20, причем на коммит уходило до полутора минут.

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 548
  • Карма: 119
Вопрос такой: какова лучшая практика в использовании транзакции - сколько операций рекомендуется проводить в рамках одной транзакции, как лучше поступать - все запихивать в одну транзакцию, или последовательно открывать/закрывать несколько транзакций, в рамках каждой из них выполняя однотипные операции.

1. В документации вроде была рекомендация закрывать транзакцию сразу по использованию, т.е. не держать долго открытой.
2. В твоем случае должно хватить одной транзакции.
3. Лучше использовать одну транзакцию чем несколько, это быстрее, т.к. закрытие, открытие транзакции требует времени.
4. Не всегда возможно обойтись одной транзакцией. Редко, бывают случае когда нужно добавить сложный объект, например блок, таблицу, стиль и т.д. и закрыть транзакцию, чтобы объект появился в чертеже. Затем снова открыть транзакцию и произвести действия, что-то добавить, изменить. Иначе будут ошибки и вылеты в какой-нибудь версии автокада. Это нигде не описано.

Оффлайн Lemieux

  • ADN OPEN
  • ****
  • Сообщений: 393
  • Карма: 21
Не всегда возможно обойтись одной транзакцией. Редко, бывают случае когда нужно добавить сложный объект, например блок, таблицу, стиль и т.д. и закрыть транзакцию, чтобы объект появился в чертеже. Затем снова открыть транзакцию и произвести действия, что-то добавить, изменить. Иначе будут ошибки и вылеты в какой-нибудь версии автокада. Это нигде не описано.
Чтобы объект появлялся на чертеже транзакцию необязательно закрывать.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
Lemieux,
Поясни свою мысль.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 828
  • Карма: 168
    • Мои плагины к Автокаду
Чтобы объект появлялся на чертеже транзакцию необязательно закрывать.
Я как раз о том же писал, что Commit ничего не делает, все изменения применяются ко всей БД сразу же, до Commit и видны из всех остальных транзакций и иногда видны даже пользователем (что полностью не соответствует понятию транзакция в реляционных базах данных). Никакой изоляции. Просто удобный способ замены using... ну еще откат полезен бывает, да...

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
Я как раз о том же писал, что Commit ничего не делает,
Commit равносилен выполнению операции Close для всех объектов, участвующих в транзакции. Поэтому сказать, что он ничего не делает - неправильно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 828
  • Карма: 168
    • Мои плагины к Автокаду
Commit равносилен выполнению операции Close для всех объектов
А что фактически делает операция Close ? Какие-то манипуляции с неуправляемой памятью? Все свойства всех объектов чертежа уже реально применены ДО закрытия транзакции.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
Какие-то манипуляции с неуправляемой памятью?
Ну в принципе да. И кроме того срабатывают реакции AutoCAD на закрытие/изменения объектов.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей НикифоровАвтор темы

  • ADN OPEN
  • Сообщений: 13
  • Карма: 2
  • Энтузиаст-одиночка
Честно говоря, я задавал этот вопрос в контексте конкретной задачи, поскольку изначально думал, что что-то не так делаю с транзакцией. Несмотря на все мои усилия, до сих пор не добился результата, прошу по возможности ответить - что я не так делаю. Задумка такая: на входе имею список полных названий файлов *.dwg, в цикле читаю базу данных каждого файла (без открытия документа), в каждой базе читаю список листов (layout), открываю каждый лист на чтение и читаю его свойства - имя (LayoutName), порядок следования (TabOrder) и размер области печати (PlotWindowArea). Все это сохраняю в отдельные списки и завершаю на этом работу с файлами. При всех этих операциях при отладке все нормально, но как только выходим за конечные скобки цикла перебора файлов VisualStudio выдает отдельное окно примерно с таким сообщением: acdbmgd.dll пытается совершить запись в область памяти, защищенную от записи. AutoCAD в этот момент фаталит. Иногда этого не происходит (сразу), но при закрытии чертежа, который был открыт при запуске этой команды, AutoCAD все равно падает, т.е. ошибка может проявиться либо сразу после завершения работы с внешними файлами, либо потом.

Вот код:
               
Код - C# [Выбрать]
  1. // список имен файлов
  2.                 List<string> FileNames = new List<string>();
  3.                 // здесь как-то получаем их имена...
  4.                 // пробегаемся по всем файлам
  5.                 foreach (string sFileName in FileNames)
  6.                 {
  7.                     // создаем пустую базу данных
  8.                     using (Database dbCurrent = new Database(false, true) as Database)
  9.                     {
  10.                         dbCurrent.ReadDwgFile(sFileName, FileOpenMode.OpenForReadAndAllShare, true, string.Empty);
  11.                         dbCurrent.CloseInput(true);
  12.                        
  13.                         //стартуем транзакцию
  14.                         using (Transaction tActiveTransaction = dbCurrent.TransactionManager.StartTransaction())
  15.                         {
  16.                             // получаем коллекцию объектов из словаря LayoutDictionaryId
  17.                             DBDictionary dbdLayouts = (DBDictionary)tActiveTransaction.GetObject(dbCurrent.LayoutDictionaryId, OpenMode.ForRead);
  18.                             // определяем e-numerator для этой коллекции
  19.                             DbDictionaryEnumerator enLayout = dbdLayouts.GetEnumerator();
  20.                             // пробегаемся по всем членам коллекции
  21.                             while (enLayout.MoveNext())
  22.                             {
  23.                                 // получаем указатель на лист
  24.                                 ObjectId idCurrentLayout = enLayout.Current.Value;
  25.                                 Layout layCurrent = (Layout)tActiveTransaction.GetObject(idCurrentLayout, OpenMode.ForRead);
  26.                                 // если это не модель - читаем ее свойства
  27.                                 if (layCurrent.ModelType == false)
  28.                                 {
  29.                                     // имя
  30.                                     string LayoutName = layCurrent.LayoutName;
  31.                                     int TabOrder = layCurrent.TabOrder;
  32.                                     Extents2d extPlotArea = layCurrent.PlotWindowArea;
  33.                                 }
  34.                             }
  35.                             tActiveTransaction.Commit();
  36.                         }
  37.                     }
  38.                 }// при достижении этой строки AutoCAD падает, либо потом, когда закрывается документ, из которого запускалась команда
               
Можете подсказать, что я не так делаю?