22.07.2005

Особенности использования транзакций при обмене данными

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

В целях обеспечения согласованности записываемых данных, зачастую возникает желание выполнять весь алгоритм чтения сообщения обмена и записи полученных данных в базу данных в одной транзакции. Действительно, такой подход позволяет гарантировать согласованность и целостность загружаемых данных, однако при больших объемах принимаемых изменений может привести к значительному ухудшению параллельности работы пользователей. На это влияют несколько различных причин.

Транзакционные блокировки

При записи полученных элементов данных в базу данных (при выполнении метода Записать()), вызывается исключительная блокировка записываемого элемента данных, которая будет удерживаться до завершения транзакции. Исключительная блокировка означает, что заблокированный элемент данных не может быть изменен или считан в другой транзакции. Запрет на считывание распространяется только на операции чтения, выполняемые в транзакции. Операции чтения, выполняемые вне транзакции, будут выполняться.

Гранулярность блокировок

В клиент-серверном варианте для объектов данных (элементы справочников, документы, ...) выполняется блокировка уровня записи, а для необъектных данных (наборы записей регистров) выполняется так называемая блокировка диапазона ключей, что означает, что могут быть заблокированы и некоторые соседние данные.

В файловом варианте всегда выполняется блокировка уровня таблицы, что означает, что будет заблокирована целиком вся таблица, в которую записываются данные.

Объем обрабатываемых данных

Обработка больших объемов данных в одной транзакции нежелательна, поскольку, например, в файловом варианте все изменения, произведенные транзакцией, накапливаются в оперативной памяти. При записи больших объемов данных в одной транзакции это может привести к исчерпыванию свободной памяти.

В клиент-серверном варианте такой опасности нет, но все-таки записывать большие объемы данных в одной транзакции не рекомендуется (из-за проблем параллельности, блокировки тоже требуют ресурса сервера баз данных и т. п.).

 

РЕКОМЕНДАЦИИ 

Исходя из перечисленных выше причин, можно дать следующие рекомендации:

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

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

Минусами такого подхода является снижение параллельности работы пользователей в силу причин, описанных выше.

При обмене большими порциями данных имеет смысл использовать несколько транзакций при загрузке или выгрузке данных.

Например, в алгоритме загрузки данных можно использовать следующий фрагмент кода, позволяющий разбивать процесс загрузки на несколько транзакций по 1000 элементов данных (в данном случае величина 1000 – условная):

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML; 
ЧтениеXML.ОткрытьФайл(ИмяФайла); 

ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения(); 
ЧтениеСообщения.НачатьЧтение(ЧтениеXML); 

Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
НачатьТранзакцию(); Попытка Для Счетчик = 1 По 1000 Цикл Данные = ПрочитатьXML(ЧтениеXML); Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель; Данные.ОбменДанными.Загрузка = Истина; Данные.Записать(); Если Не ВозможностьЧтенияXML(ЧтениеXML) Тогда Прервать; КонецЕсли; КонецЦикла; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецЦикла; ЧтениеСообщения.ЗакончитьЧтение(); ЧтениеXML.Закрыть();

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