Я использую Qt 4.8.3 и MySQL ODBC 3.51 Driver. Когда моя транзакция завершается неудачно из-за дублирования уникального идентификатора во второй таблице, вставка в первую таблицу не откатывается. Кто-нибудь может определить ошибку?
struct Property //see OMG's Property Service
{
std::string name;
boost::any value;
Property();
Property(const std::string &inName, const boost::any &inValue):name(inName),value(inValue){}
};
Property myFunction(QSqlDatabase &db, int amount)
{
assert(db.driver()->hasFeature(QSqlDriver::Transactions) == true);
db.transaction();
QSqlQuery query(db);
Property ret("MyPropertyTag",0);
try{
query.exec("LOCK TABLES table1 WRITE, table2 WRITE");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
for(int i=0;i<amount;i++)
{
query.exec("INSERT INTO table1 (someUniqueValue, newestId, Created) VALUES ('"+QString::number(i)+"', '1', NOW())");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
query.exec("SELECT id FROM table1 WHERE someUniqueValue = '"+QString::number(i)+"'");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
if(query.next() == false) { throw std::exception("no result for insert id"); }
auto Id1 = query.value(0).toString();
query.exec("INSERT INTO table2 (table1_id, Changed, Created) VALUES ('"+Id1+"', NOW(), NOW())");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
query.exec("SELECT Id, table1_id FROM table2 ORDER BY Id DESC LIMIT 1");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); } //lets say this throws
if(query.next() == false || query.value(1).toString() != Id1) { throw std::exception("no result for inserted id"); }
auto Id2 = query.value(0).toString();
query.exec("UPDATE table1 SET newestId = '"+Id2+"' WHERE Id = '"+Id1+"'");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
}
db.commit();
ret.value = amount;
} catch(std::exception &e) {
query.finish();
db.rollback();
ret.value = std::string("error:") + e.what();
}
query.exec("UNLOCK TABLES");
query.finish();
return ret;
}
Ваши таблицы, вероятно, Myisam, изменили их на Innodb, чтобы разрешить транзакции.
Чтобы изменить AutoCommit (я не уверен, если это необходимо), вы можете попробовать это так:
mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)
но это будет работать только с текущим соединением, если вам нужно обратиться ко всем БД, вам нужно изменить переменные БД.
Других решений пока нет …