Транзакции обеспечивают целостность данных при групповых операциях, а кэширование снимает нагрузку с БД. В ядре D7 оба механизма доступны через объект Connection и кэш-менеджеры.
Подключение к БД в D7
Работа с транзакциями идёт через объект соединения Bitrix\Main\DB\Connection. Его отдаёт приложение — по умолчанию основное соединение проекта.
use Bitrix\Main\Application;
$connection = Application::getConnection(); // основное
$other = Application::getConnection('replica'); // именованное из .settings.phpЧерез Connection доступны низкоуровневые методы: query(), queryScalar(), экранирование getSqlHelper()->forSql(), а также управление транзакциями. Именованные соединения описываются в секции connections файла /bitrix/.settings.php.
Транзакции: start, commit, rollback
Транзакция гарантирует, что группа изменений применится целиком или не применится вовсе. В D7 её открывают и закрывают явно, оборачивая логику в try/catch.
$connection = Application::getConnection();
$connection->startTransaction();
try {
OrderTable::add([...]);
OrderItemTable::add([...]);
StockTable::update($id, ['QUANTITY' => $qty]);
$connection->commitTransaction();
} catch (\Throwable $e) {
$connection->rollbackTransaction();
throw $e;
}Вложенность и типичные ошибки
MySQL не поддерживает настоящие вложенные транзакции: второй startTransaction() не создаёт новый уровень, а первый commit фиксирует всё. Это частый источник ошибок в модулях, которые вызывают друг друга.
- не открывайте транзакцию внутри обработчика ORM-события, если она уже открыта снаружи;
- длинные транзакции держат блокировки строк — коммитьте как можно раньше;
- любое исключение внутри транзакции должно вести к
rollbackTransaction(); - не смешивайте DDL и DML:
ALTER TABLEв MySQL неявно коммитит транзакцию.
Если нужна атомарность на уровне бизнес-операции, держите границы транзакции в одном месте — сервисном методе, а не размазывайте по вложенным вызовам.
Виды кэша в Битрикс
Кэширование в платформе многослойное. Важно различать уровни, потому что настраиваются и сбрасываются они по-разному.
| Уровень | Класс/механизм | Что кэширует |
|---|---|---|
| Кэш данных | Data\Cache | произвольные данные и HTML |
| Управляемый кэш | Data\ManagedCache | данные с авто-сбросом по таблице |
| Тегированный кэш | Data\TaggedCache | сброс по тегам |
| ORM-кэш | setCacheTtl() | результат конкретной выборки |
Хранилище кэша (файлы, Memcached, Redis, APCu) настраивается в /bitrix/.settings.php в секции cache. На нагруженных проектах кэш выносят в Redis или Memcached, чтобы не упираться в файловую систему.
Кэширование выборок ORM
Самый простой способ ускорить чтение — включить кэш прямо в запросе методом setCacheTtl() (время жизни в секундах). ORM сохранит результат и при повторном идентичном запросе отдаст его из кэша.
$rows = ProductTable::query()
->setSelect(['ID', 'NAME', 'PRICE'])
->where('ACTIVE', 'Y')
->setCacheTtl(3600) // час
->cacheJoins(true) // кэшировать и JOIN
->fetchAll();Метод cacheJoins(true) разрешает кэшировать выборки со связями — по умолчанию из соображений консистентности они не кэшируются. Ключ кэша ORM строит из текста запроса, поэтому разные параметры дают разные записи кэша.
Управляемый и тегированный кэш
Для собственных данных удобен Data\Cache: он оборачивает вычисления в startDataCache()/endDataCache(). Чтобы сбрасывать кэш при изменении конкретных сущностей, применяют тегированный кэш.
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Application;
$cache = Cache::createInstance();
if ($cache->initCache(3600, 'brands_list', '/brands')) {
$data = $cache->getVars();
} elseif ($cache->startDataCache()) {
$taggedCache = Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache('/brands');
$data = BrandTable::getList()->fetchAll();
$taggedCache->registerTag('brand_list');
$taggedCache->endTagCache();
$cache->endDataCache($data);
}Сброс по тегу — $taggedCache->clearByTag('brand_list'). Регистрируйте такой сброс в событии onAfterAdd/onAfterUpdate сущности, чтобы кэш автоматически инвалидировался при изменении данных.
Практические рекомендации
Транзакции и кэш решают разные задачи, но вместе дают надёжность и скорость. Несколько правил из практики.
- границы транзакции — в сервисном методе, короткие и с обязательным rollback в catch;
- кэшируйте тяжёлые и часто повторяющиеся выборки, а не всё подряд;
- связывайте кэш с тегами и сбрасывайте его в ORM-событиях;
- на highload выносите кэш в Redis/Memcached, а таблицы держите на InnoDB;
- не кэшируйте персональные данные под общим ключом — учитывайте контекст пользователя.
Итог
В D7 транзакции ведутся через Connection с явными start/commit/rollback на InnoDB, а кэширование делится на кэш данных, управляемый, тегированный и ORM-кэш через setCacheTtl(). Грамотная комбинация даёт целостность записей и разгружает БД под нагрузкой.
Мы в B2Bsite настраиваем кэш-слой и хранилища (Redis, Memcached), проектируем транзакционную бизнес-логику и вычищаем узкие места производительности. Если проект должен держать тысячи запросов в секунду без потери целостности — поможем выстроить инфраструктуру.
Частые вопросы
Как открыть транзакцию в D7?
Получить соединение через Application::getConnection() и вызвать startTransaction, затем commitTransaction при успехе или rollbackTransaction в блоке catch при ошибке.
Почему транзакция не откатывается?
Скорее всего таблица на движке MyISAM, который не поддерживает транзакции. Переведите таблицы на InnoDB. Также учтите, что DDL-операции вроде ALTER TABLE неявно коммитят транзакцию.
Поддерживает ли Битрикс вложенные транзакции?
Реальной вложенности в MySQL нет: повторный startTransaction не создаёт новый уровень, а первый commit фиксирует всё. Держите границы транзакции в одном месте.
Как закэшировать выборку ORM?
Добавить в цепочку запроса setCacheTtl с временем жизни в секундах. Для выборок со связями дополнительно вызвать cacheJoins(true), иначе JOIN не кэшируются.
Чем тегированный кэш лучше обычного?
Он позволяет сбрасывать группу кэшей по тегу командой clearByTag. Регистрируя сброс в событиях сущности, вы автоматически инвалидируете кэш при изменении данных.
Где настраивается хранилище кэша?
В файле /bitrix/.settings.php в секции cache. Там задаётся тип: файлы, Memcached, Redis или APCu. На нагруженных проектах кэш выносят в Redis или Memcached.
Кэш заменяет оптимизацию запросов?
Нет. Кэш снимает регулярную нагрузку, но медленный запрос остаётся медленным при промахе кэша. Сначала добавьте индексы и оптимизируйте SQL, потом кэшируйте.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.