Н. 3, Елманова. C++Builder 3.0, архитектура "клиент/сервер" и Internet
Из других параметров серверных баз данных, которые можно переопределить с помощью компонента TDatabase, весьма важным является параметр SQLPassThruMode, определяющий, каким образом завершаются транзакции (т. е. согласованные изменения в нескольких таблицах базы данных), инициированные компонентами ТТаЫе и TQuery, и могут ли они использовать общие соединения с базой данных. Возможные значения этого параметра - NOT SHARED, SHARED AUTOCOMMIT и SHARED NOAUTOCOMMIT.
При использовании значения NOT SHARED для компонентов TQuery и компонентов ТТаЫе создаются отдельные соединения с базой данных, что позволяет избежать возможных конфликтов и непредсказуемых результатов обновления данных в ряде случаев (например, при попытке обновления одной и той же записи с помощью методов ТТаЫе и с помощью SQL-запроса на обновление данных, инициированное компонентом TQuery).
Наиболее эффективным с точки зрения минимизации соединений с базой данных значением этого параметра в большинстве случаев является значение SHARED AUTOCOMMIT. При использовании этого значения изменения каждой записи в таблицах немедленно фиксируются сервером независимо от того, к какому классу (ТТаЫе или TQuery) принадлежит компонент, их инициировавший; при этом компоненты обоих классов могут использовать общие соединения с базой данных. Однако производительность сервера и всей системы в целом при этом может снизиться за счет постоянных выполнений операции COMMIT.
Третье возможной"""значение этого параметра - SHARED NOAUTOCOMMIT. В этом случае компоненты ТТаЫе и TQuery могут также использовать одно и то же соединение с базой данных, но без завершения транзакций после редактирования каждой записи, но контроль за завершением транзакций следует осуществлять в клиентском приложении.
Свойство Transisolation компонента TDatabase определяет уровень изоляции транзакций разных пользователей друг от друга. Предположим, в процессе транзакции требуется применить значение, хранящееся в поле какой-либо таблицы, например, для проведения расчетов. С момента начала транзакции это значение может быть изменено другим пользователем, поэтому в общем случае неочевидно, какое именно значение будет использовано - реально существующее в базе данных на момент, когда оно было затребовано, или то, которое существовало на момент начала транзакции.
Значение свойства Transisolation, равное tiDirtyRead, применяется, если в этой ситуации используются ^самые последние данные, независимо от того, завершил ли изменившую их транзакцию другой пользователь. В этом случае существует потенциальная опасность применить данные, реально не
48
Компоненты Data Access, используемые в приложениях клиент/сервер
сохраненные в базе данных, если другой пользователь выполнил откат транзакции. Отметим, что не все серверные СУБД поддерживают такой режим.
Значение tiReadCommitted применяется, если нужно применить последнее значение на тот момент, когда оно затребовано, но только после того, как изменивший его пользователь завершил транзакцию. Этот режим поддерживается большинством серверных СУБД.
Значение tiRepeatableRead полностью изолирует транзакцию от вмешательства других пользователей. При его применении в течение всей транзакции используются одни и те же данные, существовавшие на момент начала транзакции, независимо от того, изменялись ли они другими пользователями. Такой режим может создать проблемы при высокой интенсивности транзакций. Представим себе, например, систему продажи авиабилетов, когда оба оператора одновременно получают данные о том, что данное место свободно, и продают два билета на одно место. В приложениях подобного рода не рекомендуется использовать значение tiRepeatableRead.
Повлиять на выполнение серверных транзакций можно также путем кэширования внесенных пользователем изменений вместо попытки немедленного сохранения их в базе данных, установив равным TRUE значение свойства Cached Updates компонента ТТаЫе или TQuery. В этом случае накопленные в локальном кэше изменения пересылаются на сервер с помощью метода ApplyUpdates() компонента ТТаЫе или TQuery либо с помощью одноименного метода компонента TDataBase.	*
Кэширование изменений полезно по многим причинам. Во-первых, такой метод ввода данных снижает нагрузку на сеть, так как взаимодействие клиента с сервером происходит не постоянно, как в случае непосредственного редактирования таблиц на сервере, а эпизодически. Во-вторых, если сохранение кэшированных данных на сервере не удалось, например из-за блокировок обновляемых записей другими пользователями, этот метод возвращает значение BepHofalse, но при этом изменения сохраняются в кэше, что позволяет повторить попытку сохранения данных позже либо внести в изменяемые данные необходимые коррективы. Изменения также можно отменить с помощью метода CancelUpdatesQ.
Отметим, что выполнение метода ApplyUpdatesQ инициирует транзакцию на сервере, которая завершается после внесения всех изменений из кэша в базу данных, и лишь после успешного ее завершения внесенные Данные удаляются из кэша. Поэтому до выполнения метода ApplyUpdates() серверные данные остаются неизмененными, что позволяет, если этого требует логика клиентского приложения, проанализировать потенциальные изменения, внести в них коррективы и лишь затем сохранить их в базе данных.
Рассмотрим простейший пример использования компонента Database и Кэширования данных. Для этой цели скопируем на сервер ORACLE 7 таб-
49