Как правильно отключаться от базы и завершать работу приложения?

Обсуждение возникших проблем, предложений и ошибок UniDAC компонентов
Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 08:11

У меня вот такая проблема иногда:
Project raised exception class EIBCError with message 'cannot disconnect database with open transactions (1 active)'
как и здесь:
https://forums.devart.com/viewtopic.php ... 63#p123863
Но закономерность не могу выяснить.

Т.е. получается, что на момент закрытия приложения есть одна (всегда одна) активная транзакция.
Если у компоненты-транзакции (TUniTransaction) есть свойство DefaultCloseAction, то оно должно работать.

Есть класс, в котором одно соединение TUniConnection и две транзакции TUniTransaction: одна читающая и одна пишущая.
Идея такая же, как у библиотеки FibPlus: читающая транзация постоянно открыта, а пишущая транзакция постоянно закрыта и открывается только на момент запись данных в базу, т.е. она максимально короткая.

Код: Выделить всё

procedure TObjectsSearch.InitDB;
begin
  connNotify := TUniConnection.Create(nil);
  InterBaseUniProvider1    := TInterBaseUniProvider.Create(connNotify);
  connNotify.ProviderName  := 'InterBase';
  connNotify.ConnectString := fConnectionString;
  connNotify.AutoCommit    := False;

  transW := TUniTransaction.Create(connNotify);
  transW.IsolationLevel     := ilCustom;
  transW.DefaultCloseAction := taRollback;
  transW.DefaultConnection  := connNotify;
  transW.SpecificOptions.Values['Params'] := 'write;nowait;rec_version;read_committed';

  transR := TUniTransaction.Create(connNotify);
  transR.IsolationLevel     := ilCustom;
  transR.DefaultCloseAction := taRollback;
  transR.DefaultConnection  := connNotify;
  transR.SpecificOptions.Values['Params'] := 'read;nowait;rec_version;read_committed';

  connNotify.DefaultTransaction := transR;

  connNotify.Connect;
деструктор класса

Код: Выделить всё

destructor TObjectsSearch.Destroy;
begin
  if Assigned(connNotify) then
  begin
    if connNotify.InTransaction then
      connNotify.Rollback;

    if connNotify.Connected then
      connNotify.Disconnect;

    connNotify.DisposeOf;
  end;

  inherited;
end;
ЧЯДНТ?
Спасибо.
Delphi Tokyo, Firebird 3, UniDAC 7.1.4.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 09:43

тут есть кто-нибудь?

ViktorV
Devart Team
Сообщения: 212
Зарегистрирован: Чт 31 июл 2014 09:52

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение ViktorV » Вт 09 июл 2019 09:45

К сожалению, мы не можем воспроизвести проблему в нашем окружении на основании предоставленных вами данных.
Чтобы дать вам быстрый и полный ответ на ваш вопрос, пожалуйста, составьте и вышлите нам, с помощью контактной формы https://www.devart.com/company/contactform.html, полный пример, демонстрирующий указанное вами поведение, включающий скрипты для создания и заполнения объектов БД.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 09:51

Т,е. в моём коде ошибок нет?

ViktorV
Devart Team
Сообщения: 212
Зарегистрирован: Чт 31 июл 2014 09:52

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение ViktorV » Вт 09 июл 2019 10:06

При выполнении указанного вами кода мы не получаем указанную вами ошибку.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 10:19

Напишите, как правильно завершить все транзакции.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 10:35

Хорошо было бы, если бы в исключении было бы больше информации.
ID подключения, ID транзакции, SQL запрос(ы), чтобы можно было бы быстрее такую проблему решить

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 10:54

В общем, судя по SQL-монитору, создавалось несколько одинаковых Connection, а уничтожалось только одно.

ViktorV
Devart Team
Сообщения: 212
Зарегистрирован: Чт 31 июл 2014 09:52

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение ViktorV » Вт 09 июл 2019 11:24

Если TUniTransaction.DefaultConnection.AutoCommit установлено в True, транзакции будут автоматически завершаться после любого изменения данных, иначе вам следует самостоятельно завершить транзакции.
Свойство TUniTransaction.DefaultCloseAction отвечает за поведение незавершенной транзакции при закрытии коннекта, приложения или возникновения ошибки.
Вы можете увидеть номер транзакции используя dbMonitor или следующий код:

Код: Выделить всё

  TransactionID := TDBAccessUtils.GetMultiTransactionID(UniQuery.Transaction));
Если это не поможет в решении задачи, как мы уже писали, чтобы дать вам быстрый и полный ответ на ваш вопрос, пожалуйста, составьте и вышлите нам, с помощью контактной формы https://www.devart.com/company/contactform.html, полный пример, демонстрирующий указанное вами поведение, включающий скрипты для создания и заполнения объектов БД.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 12:34

Я уже разобрался.

Cоздавалось несколько одинаковых компонент типа TUniConnection, а уничтожалась в итоге только одна компонента. Поэтому и оставались активные транзакции. Непонятно только почему всегда была активная транзакция, хотя в приложении было 5-10 или больше подключений, как показывал SQL-монитор.

ViktorV
Devart Team
Сообщения: 212
Зарегистрирован: Чт 31 июл 2014 09:52

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение ViktorV » Вт 09 июл 2019 12:38

Возможно, данное поведение связано с особенностью работы Firebird: InterBase/Firebird требует активной транзакции для любой операцией с данными, даже для открытия датасета. Поэтому при вызове TUniQuery.Open проверяется запущена ли связанная с ним транзакция и, если это не так - она автоматически запускается.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Вт 09 июл 2019 12:47

Насколько я знаю, у Firebird нет никакого механизма автоматического создания/старта транзакций.
Поэтому за старт транзакций отвечают сами компоненты доступа (UniDAC, FireDAC либо FibPlus).
Например, у FibPlus есть свойства, отвечающие за Autostart transaction. И если отключить Autostart transaction у FibPlus, то при попытке открыть датасет появляется ошибка, что нет активной транзакции.
Поэтому я искал что-то подобное и у UniDAC, но не нашёл и подумал, что Autostart transaction в библиотеке UniDAC где внутри и не управляется программистом, ну типа оно просто есть.

ViktorV
Devart Team
Сообщения: 212
Зарегистрирован: Чт 31 июл 2014 09:52

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение ViktorV » Ср 10 июл 2019 07:41

Рады слышать, что проблема решена.
Компоненты UniDAC не содержпт свойтсв подобных Autostart transaction.
Обращайтесь к нам, если у Вас возникнут вопросы по UniDAC.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Ср 10 июл 2019 14:13

Компоненты UniDAC не содержпт свойтсв подобных Autostart transaction.
Я не о наличии свойств, а о том, что компоненты сами, без моего участия стартуют транзакции.
У меня в коде вот так:

Код: Выделить всё

      sqlExec.ParamByName('LASTNAME').AsString      := User.LastName;
      sqlExec.ParamByName('LANGUAGE_CODE').AsString := User.LanguageCode;

      try
        sqlExec.Execute;
        if sqlExec.Transaction.Active then
          sqlExec.Transaction.Commit;
Как видите, строка "sqlExec.Transaction.StartTransaction" отсутствует...
ошибок нет и данные в базу сохраняются
Последний раз редактировалось Akella Пн 04 янв 2021 12:59, всего редактировалось 2 раза.

Akella
Сообщения: 217
Зарегистрирован: Пн 02 апр 2012 14:41

Re: Как правильно отключаться от базы и завершать работу приложения?

Сообщение Akella » Чт 11 июл 2019 07:05

Компоненты UniDAC не содержпт свойтсв подобных Autostart transaction.

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



У меня в коде вот так:

Код: Выделить всё

      sqlExec.ParamByName('LASTNAME').AsString      := User.LastName;
      sqlExec.ParamByName('LANGUAGE_CODE').AsString := User.LanguageCode;

      try
        sqlExec.Execute;
        if sqlExec.Transaction.Active then
          sqlExec.Transaction.Commit;
Как видите, строка "sqlExec.Transaction.StartTransaction" отсутствует...
ошибок нет и данные в базу сохраняются

Закрыто