Russian Qt Forum
Апрель 18, 2024, 22:40 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 ... 12 13 [14]   Вниз
  Печать  
Автор Тема: Транзакции Interbase  (Прочитано 145363 раз)
joker
Новичок

Offline Offline

Сообщений: 49


Просмотр профиля
« Ответ #195 : Август 19, 2015, 14:27 »

Наткнулся еще на один артефакт - для сборки под Linux зачем то закоментирована линковка lfbclient. Для правильной сборки диез (#) нужно убрать

ibpp.pri

Код:
DEPENDPATH  += $$PWD/core
INCLUDEPATH += $$PWD/core
HEADERS     += $$PWD/core/ibpp.h
SOURCES     += $$PWD/core/all_in_one.cpp

unix{
  #LIBS    += -lfbclient  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< вот тут
  DEFINES += IBPP_LINUX
  DEFINES += IBPP_GCC
}
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #196 : Сентябрь 21, 2015, 23:18 »

Проверил со стандартным драйвером IBase - там такого поведения нет - всем кто будет использовать продвинутый рекомендую об этом помнить )
А вот у меня и со стандартным похожий косяк.
Код
C++ (Qt)
m_query->prepare("insert into RESULTS (RES_ID) values (?)");
QSqlDatabase::database().transaction();
for (const SigPac &sig : sigs) {
   m_packets[sig.id] = sig;
   m_query->addBindValue(sig.id);
   if (!m_query->exec()) {
       qCritical() << m_query->lastError();
   }
}
QSqlDatabase::database().commit();
При первом срабатывании этого участка кода всё в порядке - вставляется некоторое количество записей, а вот для второго и далее имею при вызове exec ошибку:
QSqlError("-901", "Unable to execute query", "invalid transaction handle (expecting explicit transaction start)").
Как это лечить?
« Последнее редактирование: Сентябрь 21, 2015, 23:21 от xokc » Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #197 : Май 02, 2016, 05:41 »

Мучения с драйверами БД в QT привели к мысли написания своих классов работы с БД. За основу взял код этого драйвера (по сути тащил все нужные методы, чтобы с нуля не разбираться с IBPP). И интересный вопрос а вообще есть вменяемая и подробная инструкция по написанию плагинов - драйверов БД. Я что-то не встречал - может упустил... Или каждый желающий разбирается сам? Особенно радует, что от версии к версии QSqlCashedResult и другие потроха меняются, и приходится свои классы-плагины БД все время перепиливать, по ходу разбираясь как это будет правильно сделать...

Хотя в текущей системе Qt писать такой плагин все равно нет никакого желания из-за одного огромного ограничения - НЕТ ВОЗМОЖНОСТИ ЯВНОГО УПРАВЛЕНИЯ ТРАНЗАКЦИЯМИ (Как они вообще это упустили? Что за программу можно более менее серьезную без явного управления транзакциями написать?).

С одной стороны такая возможность косвенно есть

 - вариант первый через описанный в этой теме драйвер - то есть при каждом вызове функции transaction() будет стартовать новая транзакция (но не будет удаляться старая в отличие от стандартного драйвера) и автор даже умудрился придумать как костылем туда передавать ее параметры (чего кстати тоже очень не хватает в Qt системе). НО все последующие созданные QSqlQuery будут уже выполняться в контексте последней созданной транзакции и этого через текущую систему Qt не изменить - а что тут плохого? А вот что - если есть основная программа (к примеру берем главное окно), и нам нужно открыть модальное диалоговое окно которое будет работать в контексте своей транзакции - тогда при открытии окна мы вызываем transaction, работаем с окном, при закрытии окна вызывается commit() или rollback() - и все нормально, А вот если окно нам нужно не модальное - то все плохо. Т.к. если это окошко (ил процесс какой-то) запустил транзакцию, то и в главном окне все последующие созданные QSqlQuery будут работать в контексте этой запущенной последней транзакции, что совсем не хорошо, и может привести к очень запутанным ошибкам в самой программе. Ведь параметры основной транзакции и той, что в конкретном диалоговом окне могут быть совсем разные. Окна только для примера - то же самое с любыми условно параллельными процессами в программе.

- вариант второй использовать во всех местах, где нужна отдельная транзакция новое соединение с БД - то есть не экземпляр QSqlDatabase, а именно новое соединение с новым "connection name" пусть даже созданное через функцию clone. На первый взгляд приемлемо - но на деле тормоза, т.к. запрашивается новое соединение с БД на сервере, со всеми вытекающими, да и работать с этим совершенно неудобно.

Естественно я пробовал оба эти варианта притворить в жизнь. Мое мнение - КОСТЫЛИ, да и только.

Что нам надо в реальности:

класс БД
класс Транзакцию, которая создается на основе БД, в которую можно передавать параметры транзакций Firebird
класс Query, который явно связывается с транзакцией, с простым кешем для реализации seek  и как следствие first, next  и т.д.

Этот минимум можно дополнить классом-одиночкой DBManager который вернет по алиасу нужный класс БД и нужную транзакцию в любом месте программы, чтобы не передавать это добро в качестве параметров в конструкторы диалоговых окон и т.д.

Все это реализуемо через IBPP. Голый IBPP  не хочется использовать, т.к. это неудобно хочется все проверки с эксепшенами оставить в тонкой обертке, на выходе которой будут понятные и простые для любого программиста функции bool.

Может я запутался и не прав? Или каждый свои такие классы давно уже наваял и никто не делится?
« Последнее редактирование: Май 02, 2016, 05:52 от break » Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #198 : Май 02, 2016, 05:45 »

Проверил со стандартным драйвером IBase - там такого поведения нет - всем кто будет использовать продвинутый рекомендую об этом помнить )
А вот у меня и со стандартным похожий косяк.
Код
C++ (Qt)
m_query->prepare("insert into RESULTS (RES_ID) values (?)");
QSqlDatabase::database().transaction();
for (const SigPac &sig : sigs) {
   m_packets[sig.id] = sig;
   m_query->addBindValue(sig.id);
   if (!m_query->exec()) {
       qCritical() << m_query->lastError();
   }
}
QSqlDatabase::database().commit();
При первом срабатывании этого участка кода всё в порядке - вставляется некоторое количество записей, а вот для второго и далее имею при вызове exec ошибку:
QSqlError("-901", "Unable to execute query", "invalid transaction handle (expecting explicit transaction start)").
Как это лечить?
Наверное поздно я сюда заглянул - ну так на первый взгляд как раз то о чем я и говорил, у Вас создается QSqlQuery и припарится в контексте одной транзакции, а потом стартуется другая и стандартный драйвер видимо пытается выполнить ваш Query в новосозданной транзакции, но отпрепаренный в другой - предыдущей. И голову у него сносит... Это все следствие кривости архитектуры, как будто методы transaction, commit и rollback  были потом сбоку придуманы... Я давно не пользовался стандартным драйвером, но он вроде как не может иметь в одном соединении несколько транзакций, а значит... значит надо глубоко копать, что именно происходит, но явно ничего с текущей системой красиво сделать не получится... или пусть меня кто-то поправит...
Лечить костылями... Эх...
« Последнее редактирование: Май 02, 2016, 05:50 от break » Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #199 : Июль 13, 2016, 02:48 »

Ввиду того, что никто не сказал, что я все таки запутался - написал свои тонкие обертки над IBPP как и планировал выше, полностью выкинул из проекта QtSql  и пользуюсь с удобством и удовольствием уже длительное время.
Записан
Страниц: 1 ... 12 13 [14]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.264 секунд. Запросов: 23.