Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: asvil от Январь 14, 2011, 20:40



Название: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: asvil от Январь 14, 2011, 20:40
Маленький класс для автороллбэка либо коммита.
Не используйте для ORACLE DDL.
header
Код:
#ifndef AUTOTRANSACTION_H
#define AUTOTRANSACTION_H

#include <QtSql/QSqlDatabase>

class AutoTransaction
{
public:
    AutoTransaction(const QSqlDatabase &db = QSqlDatabase::database());
    virtual ~AutoTransaction();
    virtual void commit();
private:
    QSqlDatabase db;
    bool needCommit;
};

#endif // AUTOTRANSACTION_H

source
Код:
#include "autotransaction.h"

AutoTransaction::AutoTransaction(const QSqlDatabase &database) :
  db(database)
{
  needCommit = db.transaction();
}

AutoTransaction::~AutoTransaction()
{
  if (needCommit)
    db.rollback();
}

void AutoTransaction::commit()
{
  if (needCommit) {
    db.commit();
    needCommit = false;
  }
}
Использование:
Код:
AutoTransaction transaction(ourDatabase);

foreach(const QString &line, lines) {
  ...
  QSqlQuery query(ourDatabase);
  query.exec("INSERT ....");
  if (corruptedFile) {
    return;
  }
  ...
}
transaction.commit();
Своровал у друга.


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: White Owl от Январь 14, 2011, 20:57
Простите, а чем не устраивает просто посылать commit/roolback?
Код:
QSqlDatabase::database().commit();
или даже
Код:
qry.driver().transactionCommit();


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: Пантер от Январь 14, 2011, 21:07
Ну, так уж точно не забудешь перед return сделать роллбэк.


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: asvil от Январь 15, 2011, 00:11
Ага, Пантер, верно подсказывает. Простите неправильно записал пример использования.
Код:
AutoTransaction transaction(ourDatabase);

foreach(const QString &line, lines) {
  ...
  QSqlQuery query(ourDatabase);
  query.exec("INSERT ....");
  if (corruptedFile) {
    ...
    return;
  }
  if (anotherFlag) {
    ...
    if (smthWrong) {
          .......
              if ().........
                    ........
                     
                     ... if ().....
                           return;

                     if ()
                             return;
                return;
 ..............................return;
       
    }
  }
  ...
}
transaction.commit();
Хотя, оспорте, а то так неинтересно.


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: White Owl от Январь 15, 2011, 02:44
Хотя, оспорте, а то так неинтересно.
А запросто :)

Код:
AutoTransaction transaction(ourDatabase);
QSqlQuery query(ourDatabase);
if(! query.execute("insert ..." ) ) return;
transaction.commit();
if(! query.execute("update ... ") return;  // Что будет?
transaction.commit();  // будет ли что-то?
убери переменную needCommit и всегда запрашивай существование транзакции.


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: MoPDoBoPoT от Январь 15, 2011, 12:02
А ещё в Oracle есть такая особенность: после выполнения DDL оператора, происходит неявный коммит.


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: ритт от Январь 15, 2011, 19:25
зачем оно виртуал?
и зачем оно не инлайновое?


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: asvil от Январь 17, 2011, 22:34
Константин, авторское java-style решение:)
Павлик, спасибо уточнил сферу применения.
White Owl, а как запрашивать существование транзакции?


Название: Re: QMutexLocker паттерн для QSqlDatabase::transaction()
Отправлено: White Owl от Январь 18, 2011, 19:49
White Owl, а как запрашивать существование транзакции?
а... select @@trancount ... для некоторых баз данных. К сожалению, универсально это узнать нельзя.
Значит надо добавлять явный запрос на начало второй транзакции. И использовать как-то так:
AutoTransaction transaction(ourDatabase);
Код:
QSqlQuery query(ourDatabase);
if(! query.execute("insert ..." ) ) return;
transaction.commit();
transaction.begin();
if(! query.execute("update ... ") return;