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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Firebird Непонятное с транзакциями  (Прочитано 9888 раз)
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 в БД не попадет. Это конечно утешает - но мало.
Как правильно оформить по сути атомарную операцию -  в чем моя ошибка?
Записан
MoPDoBoPoT
Гость
« Ответ #1 : Июль 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;
}
 
« Последнее редактирование: Июль 04, 2010, 23:44 от Павлик » Записан
varkon
Гость
« Ответ #2 : Июль 05, 2010, 00:17 »

Надо транзакцию явно начинать QSqlDatabase::transaction()
спасибо попробую. т.е. я могу быть уверен в таком случае, что либо выполнится все, либо ничего?
Попробую опишусь естественно.
« Последнее редактирование: Июль 05, 2010, 00:20 от varkon » Записан
varkon
Гость
« Ответ #3 : Июль 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;


}
все записи до "проблемы" находятся в БД.
Записан
MoPDoBoPoT
Гость
« Ответ #4 : Июль 05, 2010, 18:03 »

Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?
Записан
MoPDoBoPoT
Гость
« Ответ #5 : Июль 05, 2010, 18:10 »

Кстати, здесь query->setForwardOnly(true) как-то "не в кассу". Это же не SELECT запрос.
Записан
varkon
Гость
« Ответ #6 : Июль 05, 2010, 18:55 »

Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?
хмммм. да не должно вроде. проверю
Записан
varkon
Гость
« Ответ #7 : Июль 06, 2010, 05:26 »

Может дело в самих хранимых процедурах, то есть фиксация изменений происходит в них?
нет не происходит. Т.е. если я выполняю процедуру например в IBExpert - то требуется подтверждение транзакции.
Записан
sarbash
Гость
« Ответ #8 : Июль 06, 2010, 08:28 »

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

P.S. Прошу прощения, что-то меня не туда понесло...
« Последнее редактирование: Июль 06, 2010, 10:05 от sarbash » Записан
varkon
Гость
« Ответ #9 : Июль 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 - результат вроде тот же.
Мне нужно обращаться к соединению из разных модулей, которые грузятся динамически, поэтому использую такую схему.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #10 : Июль 06, 2010, 12:59 »

>>static QSqlDatabase db;
принципиально не нужен. Так как "QSqlDatabase is value class", что равносильно фразе "QSqlDatabase - именованный одиночка (singleton)". Т.е. обращаясь по имени соединения, как во всех примерах, ты всегда будешь получать доступ к одному и тому же соединению с БД.
Записан

Юра.
sarbash
Гость
« Ответ #11 : Июль 06, 2010, 13:22 »

1. Согласен, разница появляется только когда много кода и нечаянно забываешь прописать нужный delete... Улыбающийся
2. Если QIBASE, я -- пас, он мне с самого начала не понравился невозможностью задать параметры транзакции. Поэтому не могу больше ничего сказать по этому поводу.
Записан
varkon
Гость
« Ответ #12 : Июль 06, 2010, 13:24 »

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

1. Согласен, разница появляется только когда много кода и нечаянно забываешь прописать нужный delete... Улыбающийся
2. Если QIBASE, я -- пас, он мне с самого начала не понравился невозможностью задать параметры транзакции. Поэтому не могу больше ничего сказать по этому поводу.

ну так как мне надо работы программы под винду и линь - то мне желательно драйвер, который бы не требовал дополнительных систем (типа ODBC). Какие в таком случае варианты? В теме о транзакциях я так понял что есть возможность использовать другой драйвер - но будет ли это решением проблемы?
Записан
sarbash
Гость
« Ответ #14 : Июль 06, 2010, 13:47 »

Именно его и использую. Под Linux, правда, не пробовал, но, осмелюсь предположить, что проблем возникнуть не должно.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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