1 Востаннє редагувалося Betterthanyou (13.05.2016 20:58:32)

Тема: Qt, SQLite, Тransaction

Я хочу написати таку transaction
Якщо хоча б один із запитів не виконався то не робити нічого, схоже для цього і служить transaction

БД

Таб. "fo_word"
`_id_`    INTEGER PRIMARY KEY AUTOINCREMENT,
`_word_`    TEXT NOT NULL UNIQUE,
`_id_uk_word_`    INTEGER, FOREIGN KEY
...
(а дальше поля які поки що не відіграють ніякої ролі)

Таб. "uk_word"
`_id_`    INTEGER PRIMARY KEY AUTOINCREMENT,
`_word_`    TEXT NOT NULL


Підключаю БД

db::db()
{
    this->c_db = QSqlDatabase::addDatabase("QSQLITE");
    qDebug() << "Transactions - " << this->c_db.driver()->hasFeature(QSqlDriver::Transactions);
    this->c_db.setDatabaseName("A:/database.db");
    this->c_db.open();
}

qDebug() каже true, тобто transactions підтримується

А ось функція для вставки

void db::addWord(QString fo, QString uk)
{
    this->c_db.transaction();

    QSqlQuery *sqlQuery = new QSqlQuery(this->c_db);

    qDebug() << "1 - " << sqlQuery->prepare("INSERT INTO fo_word(_word_) VALUES (:fo);");
    sqlQuery->bindValue(":fo", fo);
    sqlQuery->exec();
    sqlQuery->prepare("INSERT INTO uk_word(_word_) VALUES (:uk);");
    sqlQuery->bindValue(":uk", uk);
    qDebug() << "2 - " << sqlQuery->exec();

    delete sqlQuery;

    this->c_db.commit();
}

І вводжу
fo = "cup"
uk = "чашка"

все поки що добре, qDebug() для 1 і 2 запиту каже true

знову вводжу
fo = "cup"
uk = "чашка"

а тут я не розумію чому знову qDebug() для 1 і 2 запиту каже true
я fo_word сказав що _word_ має атрибут UNIQUE значить перший запит не має виконатися і transaction теж не має виконуватися

Як можна вирішити таку проблему ?

Точніше не так, бо я її вирішив

тимчасове вирішення проблеми

Ну я думаю зрозуміло чому тимчасове, для того щоб вставити два рядка наврядчи потрібно та "мудрити"

void db::addWord(QString fo, QString uk)
{

int unique_uk_word ;
int unique_fo_word ;
int latest_id ;
//
QSqlQuery *sqlQuery = new QSqlQuery(this->c_db);

sqlQuery->prepare("SELECT COUNT(*) AS unique_uk_word FROM uk_word WHERE _word_ = :uk;");
sqlQuery->bindValue(":uk", uk);
sqlQuery->exec();

sqlQuery->next();
unique_uk_word = sqlQuery->value("unique_uk_word").toInt();
//
//

sqlQuery->prepare("SELECT COUNT(*) AS unique_fo_word FROM fo_word WHERE _word_ = :fo;");
sqlQuery->bindValue(":fo", fo);
sqlQuery->exec();

sqlQuery->next();
unique_fo_word = sqlQuery->value("unique_fo_word").toInt();

//
if(unique_uk_word == 0 && unique_fo_word == 0)
{

    sqlQuery->prepare("INSERT INTO uk_word(_word_) VALUES (:uk);");
    sqlQuery->bindValue(":uk", uk);
    sqlQuery->exec();

    latest_id = sqlQuery->lastInsertId().toInt();

    sqlQuery->prepare("INSERT INTO fo_word(_word_, _id_uk_word_) VALUES(:fo, :_id_uk_word_);");
    sqlQuery->bindValue(":fo", fo);
    sqlQuery->bindValue(":_id_uk_word_", latest_id);
    sqlQuery->exec();

}
else if(unique_fo_word == 0)
{

    sqlQuery->prepare("SELECT _id_ AS latest_id FROM uk_word WHERE :uk = _word_;");
    sqlQuery->bindValue(":uk", uk);
    sqlQuery->exec();

    sqlQuery->next();
    latest_id = sqlQuery->value("latest_id").toInt();

    sqlQuery->prepare("INSERT INTO fo_word(_word_, _id_uk_word_, _time_add_) VALUES(:fo, :_id_uk_word_, datetime());");
    sqlQuery->bindValue(":fo", fo);
    sqlQuery->bindValue(":_id_uk_word_", latest_id);
    sqlQuery->exec();

}

delete sqlQuery;

}

Як можна правильно вирішити таку проблему ?