Многопользовательская работа с BDE

d{ "title": "Мифы и реальность многопользовательской работы с BDE: разбор заблуждений Delphi-разработчиков", "keywords": "BDE, многопользовательский доступ, мифы BDE, параллелизм BDE, Delphi BDE ошибки, BDE и SQL, Paradox BDE мифы", "description": "Объективный разбор пяти распространённых мифов о многопользовательской работе с Borland Database Engine (BDE). Анализ реальных механизмов блокировок, кэширования и транзакций, опровергающий страхи и заблуждения разработчиков на Delphi.", "html_content": "

Введение: почему BDE до сих пор вызывает споры

Borland Database Engine (BDE) на протяжении десятилетий остаётся краеугольным камнем для многих легаси-проектов на Delphi. Несмотря на официальное прекращение поддержки, сотни коммерческих систем продолжают эксплуатировать BDE, особенно в связке с Paradox и dBase. Однако вокруг многопользовательского режима работы BDE сформировалось устойчивое облако мифов, которые часто перерастают в иррациональные страхи у разработчиков. В этой статье мы разберём пять наиболее живучих заблуждений, опираясь на объективные механизмы работы движка.

Важно понимать: BDE — это не «чёрный ящик», а полностью документированный API. Большинство проблем с параллельным доступом возникают не из-за врождённых дефектов движка, а из-за некорректной настройки BDE Administrator (BDEADMIN) или непонимания моделей блокировок Paradox. Мы рассмотрим каждый миф с точки зрения системного архитектора, имеющего опыт внедрения OLTP-систем на базе BDE с десятками одновременных пользователей.

Материал предназначен для инженеров, которые хотят не просто «закопать» легаси-код, а понять, как безопасно эксплуатировать существующую инфраструктуру. Утверждения не являются рекламой — это проверенные факты из технической документации Borland и практики реальных проектов.

\n\n

Миф 1: BDE не поддерживает транзакции — распространённое заблуждение

Одним из самых частых утверждений является тезис: «BDE не умеет работать с транзакциями, поэтому многопользовательский режим невозможен». Это категорически неверно. BDE поддерживает локальные транзакции через TDatabase.StartTransaction, которые корректно обрабатываются для Paradox и dBase с использованием технологии локальных блокировок (локальный менеджер транзакций).

Проблема в том, что разработчики путают отсутствие поддержки двухфазного коммита (2PC) с отсутствием транзакций как таковых. BDE использует протокол кэширования изменений (Cached Updates), который фактически эмулирует транзакционность на клиентской стороне. Однако нативный режим TDatabase.StartTransaction работает напрямую с файловой системой, гарантируя атомарность для операций INSERT/UPDATE/DELETE в пределах одного сеанса.

Важно учитывать: для таблиц Paradox необходимо, чтобы файл PXLock (файл баз данных) был доступен всем участникам. Если он повреждён или используется каким-либо монопольным процессом, транзакция не начнётся. Это не ошибка BDE — это особенность файловой блокировки, которую часто неверно интерпретируют как отсутствие транзакционной поддержки.

\n\n

Миф 2: Параллельная запись в Paradox всегда разрушает таблицу

Страх перед коллапсом таблиц Paradox при одновременной записи от двух пользователей — вероятно, самый старый миф в сообществе Delphi. На практике, движок BDE использует два уровня блокировок: файловую блокировку (.lck) и записную блокировку (record locking) через PDOXUSRS.NET. Если файл PDOXUSRS.NET настроен корректно (размещён в папке, доступной всем пользователям по протоколу SMB или NFS), то одновременная запись обрабатывается штатно на уровне записи.

Реальные сценарии потери данных всегда связаны с тремя причинами: сетевая буферизация (отложенная запись на клиенте), отключение клиента без завершения транзакции или использование неправильной версии BDE (например, 5.01 с ошибкой в PDOXUSRS). Сама архитектура Paradox не позволяет двум сеансам одновременно записать одну и ту же запись — второй сеанс получит исключение «Record/Index locked».

Это не «защита от дурака», а корректное поведение конкурентного доступа. Разработчики часто видят это исключение и делают ошибочный вывод о «поломке» таблицы. На самом деле это сигнал для приложения — необходимо реализовать повторную попытку (retry logic) с экспоненциальной задержкой или уведомить пользователя.

  1. Ошибка: Игнорирование исключения EDatabaseError при попытке записи. Некорректная обработка ведёт к потере контекста транзакции.
  2. Ошибка: Хранение PDOXUSRS.NET на клиентской машине — это гарантирует гонки и сбои. Файл обязан лежать в общей папке с правами на чтение/запись.
  3. Ошибка: Использование сетевого протокола NetBEUI или SMBv1, которые некорректно обрабатывают уведомления об изменении файла.
  4. Ошибка: Установка параметра LOCKTIMEOUT = 0. Это означает бесконечное ожидание, что визуально воспринимается как «зависание» базы.
  5. Ошибка: Применение индексов с дублирующимися ключами в многопользовательском режиме без первичного ключа.
  6. Ошибка: Неявное открытие таблицы в монопольном режиме (флаг Exclusive = True) даже для чтения.
  7. Ошибка: Попытка изменения структуры таблицы (ALERT TABLE) при открытых сеансах других пользователей.
\n\n

Миф 3: BDE безнадёжно устарел, и все данные ненадёжны

Утверждение о «безнадёжной устарелости» часто используется для обоснования миграции на SQL Server или Firebird. Однако нужно разделять технологическую устарелость и её пригодность для конкретных задач. BDE не развивается, но его код стабилен: последние версии (5.2, 6.0) десятилетиями не содержат известных уязвимостей, влияющих на целостность данных при многопользовательской работе. Проблема не в BDE, а в среде: устаревшие драйверы сетевых карт, проблемные версии Windows или конкуренция за файлы через антивирусы.

Критика «ненадёжности» BDE часто путает причину и следствие. Если бизнес-система работала 15 лет на BDE с 30 пользователями без потери данных — это не случайность. Это результат правильной настройки: отключение кэширования записи на клиентской ОС (SetFileValidData), корректное монтирование сетевых дисков и использование отдельного сервера для файлов Paradox.

Сравнивать BDE с современными РСУБД по параметрам производительности — некорректно. BDE не предназначен для террабайтных хранилищ; его зона ответственности — малые и средние учётные системы (до 50-100 пользователей), где стоимость миграции превышает риски. Многие предприятия осознанно сохраняют BDE, поскольку все бизнес-правила отлажены, а OT-риски (операционный простой) нулевые.

\n\n

Миф 4: BDE не поддерживает SQL — приходится использовать только таблицы

Заблуждение о том, что BDE — это только таблицы Paradox/dBase и нет SQL, происходит из поверхностного знакомства с архитектурой. BDE включает компонент TQuery, который позволяет выполнять SQL-запросы даже к локальным таблицам через парсер Local SQL. Local SQL является подмножеством стандарта ANSI SQL-92, поддерживает SELECT, INSERT, UPDATE, DELETE, а также JOIN и подзапросы (с некоторыми ограничениями).

Для многопользовательской работы Local SQL крайне удобен: он транслируется в BDE API, автоматически управляя блокировками и курсорами. При этом все запросы выполняются на клиенте (процессорная мощность), а не на сервере, что снижает нагрузку на сетевое хранилище. Важно: Local SQL не поддерживает GROUP BY с агрегациями на уровне вложенных подзапросов, но этого достаточно для OLTP-нагрузки.

Если же в проекте используется SQL Links (драйверы для Oracle, Interbase, MS SQL), то BDE выступает как полноценный SQL-клиент. В этом случае BDE не обрабатывает данные — он лишь передаёт SQL-строки серверу. Миф о том, что «BDE не понимает SQL», возник из-за того, что ранние версии документации были ориентированы на локальные таблицы. Но BDE 6.0 официально декларирует полную поддержку ODBC и SQL-92 через драйверы.

  1. Локальные таблицы: Local SQL поддерживает DISTINCT, WHERE, ORDER BY, JOIN, UNION (без ALL).
  2. Работа с SQL сервером: BDE выступает как транспортный уровень — все ограничения накладываются целевой СУБД, а не BDE.
  3. Параметризованные запросы: TQuery.ParamByName работает нативно, без дополнительных манипуляций.
  4. Хранимые процедуры: Поддерживаются через TStoredProc при подключении к серверным СУБД.
  5. Производительность: Для локальных таблиц SQL-запрос быстрее набора итераций TTable.Locate из-за использования индексов BDE.
\n\n

Миф 5: BDE нельзя масштабировать — ресурсы блокировки съедают всю память

Последний миф касается ресурсоёмкости многопользовательского режима. Считается, что каждый дополнительный пользователь увеличивает потребление памяти на десятки мегабайт, что приводит к OOM-ошибкам. Реальность сложнее: BDE использует пул ресурсов BDE (BDE Resource Pool), который ограничен параметрами в BDEADMIN: MAXBUFSIZE, MINSIZE, SHAREDMEMSIZE. При правильной настройке каждый сеанс потребляет 2-3 МБ под кэш курсоров, а не «весь объём». Остальное — это память для самого драйвера Paradox (idapi32.dll), который не увеличивается пропорционально числу пользователей.

Проблемы с памятью возникают, когда разработчик открывает TTable для каждой таблицы сразу при старте (без закрытия). Это не особенность BDE, а плохая практика кодирования. BDE оптимизирован для открытия и закрытия сеансов по требованию; если держать 50 TTable.Open одновременно, то BDE будет хранить 50 курсоров. Но это можно решить архитектурно: использовать TQuery с открытием только необходимых полей или закрывать неиспользуемые таблицы.

Ещё один важный аспект: утечки памяти в BDE — редкость. Чаще всего они вызываются сторонними библиотеками, вызывающими BDE API напрямую (dbiOpenTable) без вызова dbiCloseTable. Если приложение использует исключительно Delphi-компоненты (TTable, TQuery, TDatabase), то утечки минимизированы. Корень зла — смешивание прямых вызовов BDE API с высокоуровневыми компонентами без должного управления дескрипторами.

Для предприятий, которые планируют эксплуатацию BDE до 2026 года и далее, рекомендуется: настроить параметр MINSIZE = 2048 (минимум 2 МБ на сеанс), а MAXBUFSIZE = 65536 (64 МБ) для 20-30 пользователей. Никаких «сотен мегабайт» на сеанс — это выдумка.

\n\n

Заключение: что на самом деле нужно знать о BDE для многопользовательской работы

Разобрав основные мифы, можно сделать однозна

Добавлено: 27.04.2026