Откат транзакций Qt не работает в MySQL

Я пытаюсь использовать транзакции в соединении Qt, но не могу понять, как они работают правильно. Моя база данных представляет собой экземпляр MySQL, а таблицы используют механизм InnoDB, поэтому транзакции поддерживаются.

Я написал небольшой тест, в котором в рамках транзакции я удаляю запись в таблице и в конечном итоге создаю уже существующую таблицу. Когда сценарий создания терпит неудачу, я пытаюсь справиться с этим, откатываясь.

Я ожидаю, что при откате запись не будет удалена. Однако я получил то, что как только вызывается функция отката, запись удаляется.

#include <QApplication>
#include <QtSql>
#include <QtDebug>

int main( int argc, char **argv )
{
  QApplication app( argc, argv );

  QSqlDatabase db = QSqlDatabase::addDatabase( "QMYSQL" );

  db.setHostName( QString("XXXXX")) ;
  db.setDatabaseName( "db_test" );
  db.setUserName( "X" );
  db.setPassword( "X" );
  QSqlDatabase::database().transaction();
  QSqlQuery q;
  if( !db.open() )
  {
    qDebug() << db.lastError();
    qFatal( "Failed to connect." );
  }
  qDebug( "Connected!" );

  q.prepare("DELETE FROM vendita WHERE matricola = :m  and idOrdine = 530 and idStab = 1");
  q.bindValue(":m","0032110275928");

   if( !q.exec() ){
       qDebug("error");
       return 0;
   }

   //this fails, the table already exists
  q.prepare( "CREATE TABLE test (id INTEGER UNIQUE PRIMARY KEY, firstname VARCHAR(30), lastname VARCHAR(30))" );
  if( !q.exec() )
  {
      qDebug() << q.lastError();
      bool res =  QSqlDatabase::database().rollback();
      qDebug() << res;
      return 0;
  }
  else
  {
      qDebug() << "Table created!";
      QSqlDatabase::database().commit();
  }

  db.close();
  return 0;
}

person paolo_tn    schedule 23.05.2017    source источник


Ответы (1)


но что я получил, так это то, что как только вызывается функция отката, запись удаляется.

Выполнение оператора CREATE TABLE вызывает неявную фиксацию для вашего первого запроса (того, который вы использовали для удаления записи). Следовательно, ваша запись удаляется независимо от того, завершилась ли ошибка CREATE TABLE или нет.

Из https://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html,

Операторы, перечисленные в этом разделе (и любые их синонимы), неявно завершают любую транзакцию, активную в текущем сеансе, как если бы вы выполнили COMMIT перед выполнением оператора.

Кроме того, обратите внимание, что вы все равно не можете откатить CREATE TABLE, поскольку это одна из инструкций языка определения данных (DDL), которая определяет или изменяет объекты базы данных.

person HazemGomaa    schedule 23.05.2017
comment
Я заменил оператор ddl оператором INSERT, который пытается добавить повторяющуюся запись для первичного ключа; когда вставка не удалась, я вызываю метод отката, и все транзакции откатываются, как и ожидалось. Кроме того, мне пришлось переместить код, запускающий транзакцию после открытия соединения. Спасибо - person paolo_tn; 24.05.2017