SQLite и QSqlQuery — несколько вызовов execBatch () завершаются неудачно

У меня есть класс, который должен выполнить пакетные вставки повторно. Экземпляр QSqlQuery является членом этого класса. Сначала я попробовал этот код:

TOMCache::TOMCache(QObject *parent): QObject(parent) {
m_setWithGeoQuery.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
}

void TOMCache::flushBuffer() {
QSqlQuery &query = m_setWithGeoQuery;
query.addBindValue(m_buffer.at(0));
query.addBindValue(m_buffer.at(1));
query.addBindValue(m_buffer.at(2));
query.addBindValue(m_buffer.at(3));
query.addBindValue(m_buffer.at(4));
if(!query.execBatch())
qWarning() << "-- execBatch() failed: " << query.lastError().text();
m_buffer.clear();
m_buffer << QVariantList() << QVariantList() << QVariantList() << QVariantList() << QVariantList();
}

Это не сработало. Созданный файл SQLite имел 65536 байт, но в таблице только одна строка cache_storage (flushBuffer () вызывался много раз). Похоже, что первый вызов execBatch () выполнен успешно, а следующие вызовы молча провалились (они продолжали возвращать true). Я понял, что работает следующий код:

void TOMCache::flushBuffer() {

QSqlQuery query;
query.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
query.addBindValue(m_buffer.at(0));
query.addBindValue(m_buffer.at(1));
query.addBindValue(m_buffer.at(2));
query.addBindValue(m_buffer.at(3));
query.addBindValue(m_buffer.at(4));
if(!query.execBatch())
qWarning() << "-- execBatch() failed: " << query.lastError().text();
m_buffer.clear();
m_buffer << QVariantList() << QVariantList() << QVariantList() << QVariantList() << QVariantList();
}

У меня есть пара вопросов:

  1. Нужно ли создавать и уничтожать QSqlQuery для каждого вызова execBatch ()?

  2. Если это так, почему последующие вызовы execBatch () претендуют на успешное выполнение?

  3. Как насчет большого размера файла в первом случае? (Там только 2 таблицы, другая пуста)

Я должен отметить, что это часть приложения, работающего на ОС BlackBerry 10. Чтобы избежать создания и уничтожения QSqlQuery каждый раз, я также пытался вызвать query.clear () в конце flushBuffer (), но, похоже, он также удалил подготовленный SQL из экземпляра QSqlQuery (следующий вызов execBatch () не удался) ,

РЕДАКТИРОВАТЬ: я пытался избежать синтаксического анализа SQL каждый раз, поэтому я пытался сохранить неизменным m_setWithGeoQuery и просто скопировать его в flushBuffer ():

    QSqlQuery query(m_setWithGeoQuery);
query.addBindValue(m_buffer.at(0));
...

Удивительно, но это не работает. Он ведет себя так же, как первый фрагмент.

2

Решение

Это ошибка в Qt: https://bugreports.qt.io/browse/QTBUG-43874.
Это происходит только при соблюдении обоих условий:

  • вызывая несколько раз execBatch по одному и тому же запросу
  • Значения связаны с использованием QSqlQuery :: addBindValue

Как следствие, вы можете обойти эту ошибку, вызвав QSqlQuery :: bindValue, поэтому следующий код должен работать

TOMCache::TOMCache(QObject *parent): QObject(parent) {
m_setWithGeoQuery.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
}

void TOMCache::flushBuffer() {
QSqlQuery &query = m_setWithGeoQuery;
query.bindValue(0, m_buffer.at(0));
query.bindValue(1, m_buffer.at(1));
query.bindValue(2, m_buffer.at(2));
query.bindValue(3, m_buffer.at(3));
query.bindValue(4, m_buffer.at(4));
if(!query.execBatch())
qWarning() << "-- execBatch() failed: " << query.lastError().text();
m_buffer.clear();
m_buffer << QVariantList() << QVariantList() << QVariantList() <<     QVariantList() << QVariantList();
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]