2010-09-30 3 views
8

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

Мне нужно написать клиентское приложение, которое обращается к таблицам InnoDB, и делать некоторые операции с деталями-деталями внутри транзакций. Проведя некоторое исследование транзакций (из общей точки зрения), я смиренно сделаю вывод, что компоненты, не поддерживающие данные, и ручной SQL-код будут «идеальным сочетанием» транзакций; Но компонентов, поддерживающих данные, не было бы. Кажется, они не созданы друг для друга.

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

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

BTW, я использую Delphi 7 и в настоящее время оцениваю UniDAC как библиотеку доступа к данным.

Спасибо.

РЕДАКТИРОВАТЬ

Пример для описания аспект моего вопроса:

Представьте форму с 2 DBGrids на нем. Первая сетка - MasterGrid, и над ней находятся следующие кнопки: Добавить, Изменить & Удалить. Вторая сетка - DetailGrid. Если пользователь нажмите кнопку Добавить, затем идут так:

  • Connection.StartTransaction
  • Master.Append затем Master.Post затем Master.Edit (так мастер набора данных автоинкрементных первичный ключ, и он доступен для редактирования теперь)
  • Показать форму редактирования, в которой пользователь заполняет основные записи, а также добавлять некоторые подробные записи, используя другую форму.
  • Если пользователь нажимает кнопку «ОК», приложение будет использовать Master.Post и Connection.Commit. Если пользователь нажмет Отмена, тогда приложение выполнит Connection.Rollback.

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

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

EDIT 2

Я благодарю всех вас за ваше любезное участие. Я выбираю ответ от vcldeveloper, потому что это самое близкое решение моей текущей потребности.

+0

Привет, Cocin. Добро пожаловать в StackOverflow. Ваш вопрос не особенно ясен. Какие проблемы вы испытываете при работе с контрольными данными и транзакциями, связанными с данными? Можете ли вы изменить свой вопрос, чтобы предоставить более подробную информацию? –

+0

Почему вы говорите, что компоненты, поддерживающие данные, не подходят для транзакций? Транзакция обычно обрабатывается на уровне сеанса базы данных - если команды DML поступают из ручного SQL или не имеют большого значения. – 2010-09-30 18:38:21

ответ

3

Другие, упомянутые с использованием комбинации DatasetProvider и ClientDataset, имеют пакетное обновление, но в случае использования компонентов ADO или UniDAC вам не нужен дополнительный слой DatasetProvider + ClientDataset, поскольку оба обновления ADO и UniDAC поддерживают пакетные обновления.

Для АДО, что вы должны сделать, это установить LockType вашего набора данных ltBatchOptimistic. Для UniDAC, вы должны установить CacheUpdate property to True.

Это изменение делает набор данных в кэш все изменения, внесенные на его записей в памяти, и отправить их ALLtogether в базу данных только тогда, когда вы звоните UpdateBatch метод (ADO) или ApplyUpdates метод (UniDAC).

Теперь, что вы должны сделать, это позволить вашему пользователю вставить/отредактировать запись в главном наборе данных и любые записи, которые он/она хочет в наборе данных деталей, используя любые компоненты, которые вам нравятся. Все изменения будут кэшироваться. Когда ваш пользователь будет выполнен, вы можете начать новую транзакцию и сначала вызвать UpdateBatch (или ApplyUpdate в случае UniDAC) для базового набора данных, а затем для набора данных данных, и если все будет хорошо, совершите транзакцию.

Это сделает ваши транзакции короткими, не требуя дополнительного слоя ClientDataset.

Привет

5

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

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

TADOConnection >> TADODataSet >> TDataSetProvider >> TClientDataSet >> TDataSource >> TDBEdits и т.д.

Теперь все изменения кэшируются в TClientDataSet, и вы можете вызвать его метод ApplyUpdates, чтобы опубликовать все изменения в одной быстрой транзакции. Имейте в виду, что также возможно использовать несколько TADODataSets и несколько TClientDataSets для структуры master-detail (-detail-etc) с вложенными наборами данных. Все изменения мастер-детали также могут кэшироваться и применяться в одной партии в одной транзакции. Дополнительную информацию об этом можно найти в справочных и других источниках. Сначала это непросто. Но если вы поняли, что это легко и предлагает массу возможностей. (Автономное редактирование, рассмотрение изменений до их применения и т. Д.)

+0

Да, ваше описание верное. Спасибо. Хотя это кажется несколько довольно сложным, я узнаю об упомянутой вами цепочке компонентов как одном из возможных решений. – Cocin

0

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

2

Чтобы избежать необходимости выполнения крупных сделок я использую DataSetProviders и ClientDataSets (даже локально).

Рассмотрите возможность использования этого как своего рода кеша, и он дает вам лучшее из обоих миров. Вы можете использовать элементы управления, управляемые данными, для упрощения работы во время работы с пользовательским интерфейсом. Действия пользователя над наборами данных «записываются» с помощью ClientDataSets (вид кеша базы данных).

Когда пользователь готов к СОХРАНИТЬ изменения в базу данных (например, данные счета-фактуры все на месте), вы называете ApplyUpdates метод для набора данных (ов).

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

Если у вас более сложные отношения, вы можете вызвать StartTransaction, прежде чем начинать применять обновления для всех задействованных наборов ClientDataSet, а также при завершении вызова Commit или Rollback при необходимости). Логика для провайдера - если соединение имеет активную транзакцию при вызове ApplyUpdates, то она ничего не делает с транзакцией, а просто публикует изменения в базе данных, предполагая, что вы контролируете транзакцию.

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

Мои 2 цента.

1

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

Общее решение, как уже было сказано, заключается в использовании промежуточного уровня (ClientDataSet). Но реальная проблема с вашим сценарием заключается в том, что вы не можете получить значение автоинкремента для мастер-таблицы без Master.Append и Master.Post, и, следовательно, вы начинаете транзакцию задолго до того, как она действительно понадобится.

Так что, если вы не хотите использовать промежуточный ярус и до сих пор используют компоненты для работы с данными с коротким записи операции вы должны думать о базе данных, которая поддерживает получение autoincremented значения без выполнения INSERT (в основную таблицу). Пример: База данных Firebird, а компоненты доступа к данным FibPlus для Firebird полностью поддерживают эту функцию.

+0

Некоторые базы данных заставляют пользователя использовать очень короткую транзакцию, потому что они не могут хорошо обрабатывать параллелизм. Но транзакция заключается в защите целостности и согласованности данных. Как пишет Tom Kyte (asktom.oracle.com): «Транзакция должна быть такой большой, какой должна быть [...] Транзакция должна быть ровно столько, сколько должно быть (но уже не). Транзакции не существует для удобства компьютера или его программного обеспечения. Они должны защищать ваши данные ». – 2010-10-01 11:00:27