Russian Qt Forum

Qt => Базы данных => Тема начата: varkon от Июль 04, 2010, 23:21



Название: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 04, 2010, 23:21
Есть код двух функций:
Код:
int dmModule::modifyRegDoc(TDocumentItem item,QString op){
    QString string_query = "execute procedure regdoc_modify(:did,:wid,:gid,:smid,:direct,:gcount,:operid)";
    QSqlQuery *query = new QSqlQuery(dmModule::db);
    query->prepare(string_query);
    query->bindValue(":did", item.id);
    query->bindValue(":wid",wid);
    query->bindValue(":gid",item.getGoodId());
    query->bindValue(":smid",item.getMetricId());
    query->bindValue(":direct",item.getDirect());
    query->bindValue(":gcount",item.getCount());
    query->bindValue(":operid",op);
    query->exec();
    if(query->lastError().isValid()){
        QMessageBox::about(0,"errror",query->lastError().text()+query->executedQuery());
        delete query;
        return 0;
    }
    delete query;
    return 1;
}
и
Код:
int dmModule::modifyRegInventory(const int gid, const int smid, const int wid,const int amid, const double count){
    QString query_str = "execute procedure reginventory_modify(?,?,?,?,?)";
    QSqlQuery *query = new QSqlQuery(dmModule::db);
    query->prepare(query_str);
    query->addBindValue(gid);
    query->addBindValue(smid);
    query->addBindValue(wid);
    query->addBindValue(-1);
    query->addBindValue(count);
    query->setForwardOnly(true);
    query->exec();
    if(query->lastError().isValid()){
        QMessageBox::about(0,"errror",query->lastError().text()+query->executedQuery());
        delete query;
        return 0;
    }
    delete query;
    return 1;

}
есть собственно то, что это использует:
Код:
int dmModule::modifyReceived(TDocument doc, QTableWidget *tb){


    for(int i = 0; i < tb->rowCount();i++){
//тут создан объект - возможна ошибка
        TDocumentItem item(tb,doc.id,i);
        item.setDirect(doc.getDirect());

        if(!modifyRegDoc(item,QString("new"))){
//проблемы тут - нет роллбека - откатывается только последняя строка - а не все

            dmBaseModule::db.rollback();
            return 0;
        }

        if(!modifyRegInventory(item.getGoodId(),
                               item.getMetricId(),
                               doc.getWereHouse(),
                               doc.id,
                               item.getCount())){
            dmBaseModule::db.rollback();
            return 0;
        }




    }
    QSqlQuery *query = new QSqlQuery(dmModule::db);
    QString query_str = "execute procedure isactive_modify(?,?)";
    query->prepare(query_str);
    query->addBindValue(doc.id);
    query->addBindValue(1);
    query->setForwardOnly(true);
    query->exec();
    if(query->lastError().isValid()){
        QMessageBox::about(0,"errror",query->lastError().text()+query->executedQuery());
        dmBaseModule::db.rollback();
        delete query;
        return 0;
    }
//по идее только здесь должно все за комиитится
    dmBaseModule::db.commit();
    delete query;


}
смысл в чем - если все нормально - то коммит выполняется. Если нет - то не одна из операций в БД не должна быть зафиксирована. Пока получается наоборот - т.е. если есть проблемы в строке например 34 - то 33 в БД будут. 34 в БД не попадет. Это конечно утешает - но мало.
Как правильно оформить по сути атомарную операцию -  в чем моя ошибка?


Название: Re: Firebird Непонятное с транзакциями
Отправлено: MoPDoBoPoT от Июль 04, 2010, 23:39
Надо транзакцию явно начинать QSqlDatabase::transaction()
Код
C++ (Qt)
int dmModule::modifyReceived(TDocument doc, QTableWidget *tb) {
   //QSqlDatabase::transaction();
   dmBaseModule::db.transaction();
 
   ...
 
   dmBaseModule::db.commit();
   delete query;
}
 


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 05, 2010, 00:17
Надо транзакцию явно начинать QSqlDatabase::transaction()
спасибо попробую. т.е. я могу быть уверен в таком случае, что либо выполнится все, либо ничего?
Попробую опишусь естественно.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 05, 2010, 17:07
Нет. К сожалению не работает. Т.е. если добавить в код :

Код:
int dmModule::modifyReceived(TDocument doc, QTableWidget *tb){
//транзакцию начали
    dmBaseModule::db.transaction();
    for(int i = 0; i < tb->rowCount();i++){
       
        TDocumentItem item(tb,doc.id,i);
        item.setDirect(doc.getDirect());
//тут в одной из итераций есть проблема
        if(!modifyRegDoc(item,QString("new"))){

            dmBaseModule::db.rollback();
            return 0;
        }
        if(!modifyRegInventory(item.getGoodId(),
                               item.getMetricId(),
                               doc.getWereHouse(),
                               doc.id,
                               item.getCount())){
            dmBaseModule::db.rollback();
            return 0;
        }




    }
    QSqlQuery *query = new QSqlQuery(dmModule::db);
    QString query_str = "execute procedure isactive_modify(?,?)";
    query->prepare(query_str);
    query->addBindValue(doc.id);
    query->addBindValue(1);
    query->setForwardOnly(true);
    query->exec();
    if(query->lastError().isValid()){
        QMessageBox::about(0,"errror",query->lastError().text()+query->executedQuery());
        dmBaseModule::db.rollback();
        delete query;
        return 0;
    }
    dmBaseModule::db.commit();
    delete query;


}
все записи до "проблемы" находятся в БД.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: MoPDoBoPoT от Июль 05, 2010, 18:03
Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?


Название: Re: Firebird Непонятное с транзакциями
Отправлено: MoPDoBoPoT от Июль 05, 2010, 18:10
Кстати, здесь query->setForwardOnly(true) как-то "не в кассу". Это же не SELECT запрос.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 05, 2010, 18:55
Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?
хмммм. да не должно вроде. проверю


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 06, 2010, 05:26
Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?
нет не происходит. Т.е. если я выполняю процедуру например в IBExpert - то требуется подтверждение транзакции.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: sarbash от Июль 06, 2010, 08:28
Странная конструкция... :)
1. Я бы квери клал на стек, само бы удалялось при выходе из функции.
2. Что за драйвер используется?
3. dmBaseModule::db - это что? Что мешает пользоваться штатной QSqlDatabase::database()?
4. dmBaseModule::db и здесь: QSqlQuery *query = new QSqlQuery(dmModule::db) -- это одна и та же база?

P.S. Прошу прощения, что-то меня не туда понесло...


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 06, 2010, 12:42
Странная конструкция... :)
1. Я бы квери клал на стек, само бы удалялось при выходе из функции.
2. Что за драйвер используется?
1. Не вижу существенной разницы.
2. QIBASE
3. dmBaseModule::db - это что? Что мешает пользоваться штатной QSqlDatabase::database()?
3. Объявлено как:
Код:
class dmBaseModule : public QObject
{
Q_OBJECT
public:
    explicit dmBaseModule(QObject *parent = 0);
    static void setDatabase(QSqlDatabase &in){dmBaseModule::db = in;};
    static QSqlDatabase& getDatabase(){return dmBaseModule::db;}
    virtual int loadTableListGoods(QObject *sender,const int &id =-1,const int &parentid =-1,const int &isgroup=0,const int &iscomplect=0)=0;

signals:

public slots:
protected:
  static QSqlDatabase db;

};
Далее неследуется:
Код:
class dmModule : public dmBaseModule
{
Q_OBJECT
public:
    explicit dmModule(QObject *parent = 0);
    virtual int loadTableListGoods(QObject *sender,const int &id =-1,const int &parentid =-1,const int &isgroup=0,const int &iscomplect=0);
<skip>...</skip>
4. dmBaseModule::db и здесь: QSqlQuery *query = new QSqlQuery(dmModule::db) -- это одна и та же база?
Вот с этим я может немного заблудился (хотя по моему это не имеет значения) - но сейчас просто переделал dmBaseModule::db - результат вроде тот же.
Мне нужно обращаться к соединению из разных модулей, которые грузятся динамически, поэтому использую такую схему.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: lit-uriy от Июль 06, 2010, 12:59
>>static QSqlDatabase db;
принципиально не нужен. Так как "QSqlDatabase is value class", что равносильно фразе "QSqlDatabase - именованный одиночка (singleton)". Т.е. обращаясь по имени соединения, как во всех примерах, ты всегда будешь получать доступ к одному и тому же соединению с БД.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: sarbash от Июль 06, 2010, 13:22
1. Согласен, разница появляется только когда много кода и нечаянно забываешь прописать нужный delete... :)
2. Если QIBASE, я -- пас, он мне с самого начала не понравился невозможностью задать параметры транзакции. Поэтому не могу больше ничего сказать по этому поводу.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 06, 2010, 13:24
>>static QSqlDatabase db;
принципиально не нужен. Так как "QSqlDatabase is value class", что равносильно фразе "QSqlDatabase - именованный одиночка (singleton)". Т.е. обращаясь по имени соединения, как во всех примерах, ты всегда будешь получать доступ к одному и тому же соединению с БД.
Ну насколько я понимаю - от этого хуже не будет? Так как я использую класс который сингелтоном не является - я таким образом гарантирую что все созданные классы обращаются к одной области памяти. Или это потенциально не верный подход?


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 06, 2010, 13:27
1. Согласен, разница появляется только когда много кода и нечаянно забываешь прописать нужный delete... :)
2. Если QIBASE, я -- пас, он мне с самого начала не понравился невозможностью задать параметры транзакции. Поэтому не могу больше ничего сказать по этому поводу.

ну так как мне надо работы программы под винду и линь - то мне желательно драйвер, который бы не требовал дополнительных систем (типа ODBC). Какие в таком случае варианты? В теме о транзакциях (http://www.prog.org.ru/topic_8509_0.html) я так понял что есть возможность использовать другой драйвер - но будет ли это решением проблемы?


Название: Re: Firebird Непонятное с транзакциями
Отправлено: sarbash от Июль 06, 2010, 13:47
Именно его и использую. Под Linux, правда, не пробовал, но, осмелюсь предположить, что проблем возникнуть не должно.


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 06, 2010, 13:52
гм. Последнее в одном из сообщений в теме говорится о проблемах с числами типа numeric? Это достаточно принципиальная ошибка. Ответа пока нет. 


Название: Re: Firebird Непонятное с транзакциями
Отправлено: sarbash от Июль 07, 2010, 08:45
Проверьте на гуглокоде ченджлог, вроде бы автор давно это пофиксил?


Название: Re: Firebird Непонятное с транзакциями
Отправлено: varkon от Июль 07, 2010, 09:09
Проверьте на гуглокоде ченджлог, вроде бы автор давно это пофиксил?

не проверял, но все значения нумерек отображаются нормально


Название: Re: Firebird Непонятное с транзакциями
Отправлено: sarbash от Июль 07, 2010, 10:23
Именно это я и имел в виду.