Компоненты Data Access


Компонент TDatabase - часть 2


Рис. 5. Редактор свойств компонента TDatabase

Помимо переопределения параметров псевдонимов или создания новых псевдонимов компонент TDatabase нередко используется для минимизации числа обращений к серверу. Как было сказано выше, компоненты TTable, TQuery и TStoredProc инициируют динамическое создание компонента TDatabase, если он в явном виде не присутствует в форме или модуле данных. Соответственно каждый раз, когда в процессе выполнения приложения создается новая форма, пользователь получает диалог ввода имени и пароля, и, что не менее существенно, происходит обращение клиентского приложения к серверу баз данных с целью выяснения существования такого пользователя, правильности его пароля, а также его прав на таблицы и иные объекты базы данных посредством вызовов функций BDE, обращающихся, в свою очередь, к функциям прикладного программного интерфейса клиентской части соответствующего сервера. Чтобы избежать этой ситуации, на форму или в модуль данных, создаваемый при запуске приложения, помещается компонент TDatabase (или несколько компонентов TDatabase, если приложение использует несколько различных баз данных), и свойство DatabaseName всех компонентов TTable, TQuer y , TStoredProc устанавливается равным не имени соответствующего псевдонима, а имени соответствующего компонента TDatabase.

Рис.7. Связь компонента TTable с компонентом TDatabase

Из других параметров серверных баз данных, которые можно переопределить с помощью компонента TDatabase, весьма важным является параметр SQLPassThruMode, определяющий, каким образом завершаются транзакции (т.е. согласованные изменения в нескольких таблицах базы данных), инициированные компонентами TTable и TQuery, и могут ли они использовать общие соединения с базой данных. Возможные значения этого параметра - NOT SHARED, SHARED AUTOCOMMIT и SHARED NOAUTOCOMMIT.

При использовании значения NOT SHARED для компонентов TQuery и компонентов TTable создаются отдельные соединения с базой данных, что позволяет избежать возможных конфликтов и непредсказуемых результатов обновлений данных в ряде случаев (например, при попытке обновления одной и той же записи с помощью методов TTable и с помощью SQL-запроса на обновление данных, инициированное компонентом TQuery).

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

Третье возможное значение этого параметра - SHARED NOAUTOCOMMIT. В этом случае компоненты TTable и TQuery могут также использовать одно и то же соединение с базой данных, но без завершения транзакций после редактирования каждой записи, но контроль за завершением транзакций следует осуществлять в клиентском приложении.

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

Значение свойства Transisolation, равное tiDirtyRead, применяется, если в этой ситуации используются самые последние данные, независимо от того, завершил ли изменившую их транзакцию другой пользователь. В этом случае существует потенциальная опасность использовать данные, реально не сохраненные в базе данных, если другой пользователь выполнил откат транзакции. Отметим, что не все серверные СУБД поддерживают такой режим.

Значение tiReadCommitted применяется, если нужно использовать последнее значение на тот момент, когда оно затребовано, но только после того, как изменивший его пользователь завершил транзакцию. Этот режим поддерживается большинством серверных СУБД.

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

Повлиять на выполнение серверных транзакций можно также путем кэширования внесенных пользователем изменений вместо попытки немедленного сохранения их в базе данных, установив равным true значение свойства Cached Updates компонента TTable или TQuery. В этом случае накопленные в локальном кэше изменения пересылаются на сервер с помощью метода ApplyUpdates() компонента TTable или TQuery.

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

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

Рассмотрим простейший пример применения компонента Database и кэширования данных. Для этой цели скопируем на сервер ORACLE 7 таблицу CLIENTS.DBF из входящей в комплект поставки C++Builder базы данных DBDEMOS (например, с помощью утилиты Data Migration Wizard) и создадим приложение для ввода данных в нее (рис. 8):




Содержание  Назад  Вперед