0

Qt4.8.3とMySQLODBC3.51ドライバーを使用しています。2番目のテーブルで一意のIDが重複しているためにトランザクションが失敗した場合、最初のテーブルの挿入はロールバックされません。誰かがエラーを見つけることができますか?

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;
}
4

1 に答える 1

0

テーブルはおそらくMyisamであり、トランザクションを許可するためにInnodbに変更しました。

AutoCommitを変更するには(必要かどうかはわかりません)、次の方法で試すことができます。

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

ただし、これは現在の接続でのみ機能します。すべてのDBに適用する必要がある場合は、DB変数を変更する必要があります。

于 2012-12-04T20:20:36.510 に答える