Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: QIBASE + транзакции, не возможно выполнить более одного раза
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Разработка баз данных
Litkevich Yuriy
Тут порешал для работы с Firebird'ом воспользоваться драйвером QIBASE, до этого работал через QODBC.
Наткнулся на проблему, более одного раза (!) не могу воспользоваться транзакцией. Выжимка из кода:
model->database().transaction();
model->submitAll();
model->database().commit();
такой код почему-то срабатывает только один раз, если его вызвать повторно, то на model->submitAll() возникает ошибка.
В Qt 4.4.3:
"QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")"

В Qt 4.6.0:
"QSqlError(-901, "Unable to execute query", "invalid transaction handle (expecting explicit transaction start)")"

Без транзакций всё работает как в аптеке, а также с транзакциями через QODBC.
Пробовал какую-то не свежую версию QFirebird, которую выкладывал один человек на прогорге, они просто падает на первой же транзакции (model->submitAll())

Может кто-нибудь просветить в чём проблема?

Окружение
Firebird - 2.1.2.18118
Windows 2000 SP4
Litkevich Yuriy
Собрал свежий драйвер QFIREBIRD, транзакция тоже выполняется только один раз. Я уже начинаю подозревать, что я где-то делаю через одно место, но в упор не вижу где. Вот тестовый код:
(вставляет 10 строк)
#include <QCoreApplication>
#include <QSqlTableModel>
#include <QSettings>
#include <QSqlDatabase>
#include <QDebug>
#include <QSqlError>

bool connectToDatabse(QSettings &s)
{
    QSqlDatabase database;
    
    QString key;
    s.beginGroup("Database");
    key = "Driver";
    if (s.contains(key)){
        database = QSqlDatabase::addDatabase(s.value(key).toString());
    }else{
        qDebug() << "Key" << key << "is absent";
        return false;
    }
    key = "DbName";
    if (s.contains(key)){
        database.setDatabaseName(s.value(key).toString());
    }else{
        qDebug() << "Key" << key << "is absent";
        return false;
    }
    key = "UserName";
    if (s.contains(key)){
        database.setUserName(s.value(key).toString());
    }else{
        qDebug() << "Key" << key << "is absent";
        return false;
    }
    key = "UserPassword";
    if (s.contains(key)){
        database.setPassword(s.value(key).toString());
    }else{
        qDebug() << "Key" << key << "is absent";
        return false;
    }
    s.endGroup();


    
    if (!database.open())
    {
        QString qerr = database.lastError().text();
        qDebug() << "Error on open DB, reson:"
                 << qerr;
        return false;
    }
    qDebug() << database;
    return true;
}

//---------------------------------------------------------------------
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    // Читаем настройки БД из INI-файла
    QSettings s("settings.ini", QSettings::IniFormat);
    if (!connectToDatabse(s))
        return 1;
    
    // Информация о таблице
    QString table("entities");
    table = table.toUpper();
    const int columnForInsert = 2;    

    QSqlTableModel *model = new QSqlTableModel();

    model->setTable(table);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();
    
    const int rowForInsert = 10;
    int cnt = 0;
    
    while (cnt < rowForInsert){
        QString value = QString("testInsert-%1").arg(cnt);
        qDebug() << value;
        cnt++;
        //-- вставляем пустую строку в модель
        int row = model->rowCount();
        if (!model->insertRow(row)){
            qDebug() << "\t" << "Insert to model - ERROR, reson:" << model->lastError();
            return 1;
        }
        //-- вставляем данные в модель
        QModelIndex insertIndex = model->index(row, columnForInsert);
        model->setData(insertIndex, value);
        
        //-- фиксируем данные в БД
        if (model->database().transaction()){
            qDebug() << "\t" << "transaction - START";
        }else{
            qDebug() << "\t" << "transaction -" << model->database().lastError();
        }
        //
        if (model->submitAll()){
            qDebug() << "\t" << "submit - Ok";
        }else{
            qDebug() << "\t" << "submit - " << model->lastError();
        }
        //
        if (model->database().commit()){
            qDebug() << "\t" << "transaction - COMMIT";
        }else{
            qDebug() << "\t" << "transaction -" << model->lastError();
        }
    }
    return 0;
}
Может кто-то ткнёт носом?
Вот вывод:
для QODBC/Qt 4.4.3
QSqlDatabase(driver=""QODBC"", database=""UNITEST"", host="""", port=-1, user=""NNN"", open=true)
"testInsert-0"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-1"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-2"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-3"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-4"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-5"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-6"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-7"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-8"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-9"
         transaction - START
         submit - Ok
         transaction - COMMIT

D:\tempData\Qt-test-18>
реально вставляются в БД все 10 записей
для QIBASE/Qt 4.4.3
D:\tempData\Qt-test-18>ee.d
QSqlDatabase(driver=""QIBASE"", database=""L:/Repository/universalDB/db/UNIVERSALDB_1_test.FDB"", host="""", port=-1, user=""NNN"", open=true)
"testInsert-0"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-1"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-2"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-3"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-4"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-5"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-6"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-7"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-8"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
"testInsert-9"
         transaction - START
         submit -  QSqlError(-901, "Unable to execute query", "Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements")
         transaction - COMMIT
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.

D:\tempData\Qt-test-18>
реально вставляется в БД толкько 1 запись
для qtfirebirdibppsqldriver trunk@9
QSqlDatabase(driver=""QFIREBIRD"", database=""L:/Repository/universalDB/db/UNIVERSALDB_1_test.FDB"", host="""", port=-1, user=""NNN"", open=true)
"testInsert-0"
         transaction - START
         submit - Ok
         transaction - COMMIT
"testInsert-1"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-2"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-3"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-4"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-5"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-6"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-7"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-8"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
"testInsert-9"
         transaction - START
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.


         submit -  QSqlError(-1, "Unable execute statement", "*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

")
         transaction - COMMIT
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.

D:\tempData\Qt-test-18>

реально вставляется в БД толкько 1 запись
Litkevich Yuriy
Продолжаю раскопки проблемы.
--1--
Заменил QSqlTableModel, на простой QSqlQuery. Все работает в любом окружении, при любой версии Qt для компиляции. Стало быть проблема именно с QSqlTableModel + Драйвер Interbse/Firebird

--2--
сегодня наткнулся на странную ситуацию.
Поставил на свой нетбук, с Вин ХП домашней, Qt SDK 2010.02 (Qt 4.6.2), запустил эту тестовую прогу уже скомпиленную с помощью Qt 4.4.3
И она работает! т.е. все десять транзакций выполняются.
Я обрадовался, скомпилил, в консоли, ту прогу в окружении Qt 4.6.2.
И она опять НЕ работает!

Этого я вообще не понял.

П.С. обновил первое сообщение, добавив полное описание окружения.

--3--
Засунув в драйвер QIBASE кучу отладки, на сегодня, выяснил только одну вещь:
Старт транзакции происходит всякий раз, с новым номером транзакции. Но, почему-то сама запись в базу (второй и последующие разы) происходит с номером транзакции, который был у первой транзакции
Litkevich Yuriy
Цитата(Litkevich Yuriy @ 19.3.2010, 16:12) *
для qtfirebirdibppsqldriver trunk@9
пробовал и с последней версией, исключений уже нет, ошибки как и при QIBASE
mishabard
Здравствуйте! Решил не создавать новую тему! Вы занимались ей год назад.
Столкнулся с той же проблемой. При удалении строки из базы данных, дает выполнить только одну транзакцию. после этого приходится только полностью делать disconect к базе, чтоб еще одну транзакцию выполнить.
У меня ubuntu 11.4 QT 4.7 Firebird 2.1 использую стандартный драйвер IBASE.
Скажите Вы нашли решение? Дело в том что если использовать QSqlQuery, то все работает, можно делать неограниченное количестов транзакций. а если использовать QSQLTableModel - то выполняет только одну транзацию и пишет
invalid transaction handle (expecting explicit transaction start) Unable to execute query. Вот код удаления строки(упрощенный):
QSqlTableModel * kassaModel;
QModelIndex index = kassaView->currentIndex();

if (!index.isValid())
return;
if (!db.transaction())
qDebug()<<db.lastError().text();

if (!kassaModel->removeRow(index.row()))
qDebug()<<" "+kassaModel->lastError().text();
invalid transaction handle (expecting explicit transaction start) Unable to execute query
kassaModel->submitAll()

db.commit()

kassaModel->select();
ViGOur
1. Нужно разбираться с моделью, почему при удалении происходит ошибка.
2. Если происходит ошибка нужно делать не commit, а rollback!
Litkevich Yuriy
Цитата(mishabard @ 4.7.2011, 20:55) *
Скажите Вы нашли решение?
нет.
mishabard
Цитата(Litkevich Yuriy @ 4.7.2011, 19:55) *
Цитата(mishabard @ 4.7.2011, 20:55) *
Скажите Вы нашли решение?
нет.

Спасибо!
Пока вышел из положения следующим образом: использую QSQLQuery не связанный с моделью TableView, Открываю транзакцию, выполняю запрос на удаление. закрываю транзакцию. после чего обновляю TableView. Может каряво и просто, но надежно работает.
lvlad
чтобы исправить проблему необходимо в файле qsqltablemodel.cpp
в методе QSqlTableModelPrivate::exec закомментировать строку:
if (editQuery.driver() != db.driver())


bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
const QSqlRecord &rec, const QSqlRecord &whereValues)
{
if (stmt.isEmpty())
return false;

// lazy initialization of editQuery
//-->> if (editQuery.driver() != db.driver()) <<--
editQuery = QSqlQuery(db);


После этого придется перекомпировать Qt или модуль QtSql
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2020 IPS, Inc.