Страница 1 из 2

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

Добавлено: Вт 09 июл 2019 08:11
Akella
У меня вот такая проблема иногда:
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.

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

Добавлено: Вт 09 июл 2019 09:43
Akella
тут есть кто-нибудь?

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

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

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

Добавлено: Вт 09 июл 2019 09:51
Akella
Т,е. в моём коде ошибок нет?

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

Добавлено: Вт 09 июл 2019 10:06
ViktorV
При выполнении указанного вами кода мы не получаем указанную вами ошибку.

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

Добавлено: Вт 09 июл 2019 10:19
Akella
Напишите, как правильно завершить все транзакции.

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

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

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

Добавлено: Вт 09 июл 2019 10:54
Akella
В общем, судя по SQL-монитору, создавалось несколько одинаковых Connection, а уничтожалось только одно.

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

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

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

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

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

Добавлено: Вт 09 июл 2019 12:34
Akella
Я уже разобрался.

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

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

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

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

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

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

Добавлено: Ср 10 июл 2019 07:41
ViktorV
Рады слышать, что проблема решена.
Компоненты UniDAC не содержпт свойтсв подобных Autostart transaction.
Обращайтесь к нам, если у Вас возникнут вопросы по UniDAC.

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

Добавлено: Ср 10 июл 2019 14:13
Akella
Компоненты 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" отсутствует...
ошибок нет и данные в базу сохраняются

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

Добавлено: Чт 11 июл 2019 07:05
Akella
Компоненты 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" отсутствует...
ошибок нет и данные в базу сохраняются