В процессе организации обмена данными следует внимательно подходить к использованию транзакций. С одной стороны, выполнение загрузки (выгрузки) данных в одной транзакции обеспечивает целостность и согласованность данных, однако с другой стороны, транзакционные блокировки снижают параллельность работы пользователей. Поэтому в каждом конкретном случае необходимо искать компромисс между скоростью и параллельностью работы пользователей, и целостностью данных.
В целях обеспечения согласованности записываемых данных, зачастую возникает желание выполнять весь алгоритм чтения сообщения обмена и записи полученных данных в базу данных в одной транзакции. Действительно, такой подход позволяет гарантировать согласованность и целостность загружаемых данных, однако при больших объемах принимаемых изменений может привести к значительному ухудшению параллельности работы пользователей. На это влияют несколько различных причин.
При записи полученных элементов данных в базу данных (при выполнении метода Записать()), вызывается исключительная блокировка записываемого элемента данных, которая будет удерживаться до завершения транзакции. Исключительная блокировка означает, что заблокированный элемент данных не может быть изменен или считан в другой транзакции. Запрет на считывание распространяется только на операции чтения, выполняемые в транзакции. Операции чтения, выполняемые вне транзакции, будут выполняться.
В клиент-серверном варианте для объектов данных (элементы справочников, документы, ...) выполняется блокировка уровня записи, а для необъектных данных (наборы записей регистров) выполняется так называемая блокировка диапазона ключей, что означает, что могут быть заблокированы и некоторые соседние данные.
В файловом варианте всегда выполняется блокировка уровня таблицы, что означает, что будет заблокирована целиком вся таблица, в которую записываются данные.
Обработка больших объемов данных в одной транзакции нежелательна, поскольку, например, в файловом варианте все изменения, произведенные транзакцией, накапливаются в оперативной памяти. При записи больших объемов данных в одной транзакции это может привести к исчерпыванию свободной памяти.
В клиент-серверном варианте такой опасности нет, но все-таки записывать большие объемы данных в одной транзакции не рекомендуется (из-за проблем параллельности, блокировки тоже требуют ресурса сервера баз данных и т. п.).
РЕКОМЕНДАЦИИ Исходя из перечисленных выше причин, можно дать следующие рекомендации: Если обмен гарантированно производится небольшими порциями данных (например, обмен производится очень часто), то имеет смысл выполнять загрузку (выгрузку) данных в одной транзакции. Преимущества такого подхода заключаются в том, что, например, в файловом варианте работы действия, сгруппированные в одну транзакцию, выполняются значительно быстрее (до определенного предела). Кроме этого, при выгрузке данных использование одной транзакции позволяет избежать несогласованности выгружаемых данных (например, когда после выгрузки документа, но до выгрузки наборов записей регистров, произошло перепроведение документа). Минусами такого подхода является снижение параллельности работы пользователей в силу причин, описанных выше. При обмене большими порциями данных имеет смысл использовать несколько транзакций при загрузке или выгрузке данных. Например, в алгоритме загрузки данных можно использовать следующий фрагмент кода, позволяющий разбивать процесс загрузки на несколько транзакций по 1000 элементов данных (в данном случае величина 1000 – условная): Копировать в буфер обменаЧтениеXML = Новый ЧтениеXML; ЧтениеXML.ОткрытьФайл(ИмяФайла); ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения(); ЧтениеСообщения.НачатьЧтение(ЧтениеXML); НачатьТранзакцию(); Счетчик = 0; Пока ВозможностьЧтенияДанных(ЧтениеXML) Цикл Данные = ПрочитатьXML(ЧтениеXML); Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель; Данные.ОбменДанными.Загрузка = Истина; Данные.Записать(); Счетчик = Счетчик + 1; Если Счетчик % 1000 = 0 Тогда ЗафиксироватьТранзакцию(); НачатьТранзакцию(); КонецЕсли; КонецЦикла; ЗафиксироватьТранзакцию(); ЧтениеСообщения.ЗакончитьЧтение(); ЧтениеXML.Закрыть(); Преимущества такого подхода заключаются в том, что, варьируя количество элементов, обрабатываемых в одной транзакции, можно добиться приемлемого компромисса между целостностью данных и параллельностью работы пользователей. |