Frage

I'm using Qt 4.8.3 and MySQL ODBC 3.51 Driver. When my transaction fails because of a duplicate unique Id in the second table the insert in the first table is not rolled back. Can anyone spot the error?

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;
}
War es hilfreich?

Lösung

Your Tables problably are Myisam, changed them to Innodb to allow transactions.

To change the AutoCommit (I'm not sure if it's necessary) you can try it this way:

mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)

but this will be working only with the current connection, if you need to apply to all the DB you need to change the DB variables.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top