У меня есть класс, который должен выполнить пакетные вставки повторно. Экземпляр 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();
}
У меня есть пара вопросов:
Нужно ли создавать и уничтожать QSqlQuery для каждого вызова execBatch ()?
Если это так, почему последующие вызовы execBatch () претендуют на успешное выполнение?
Как насчет большого размера файла в первом случае? (Там только 2 таблицы, другая пуста)
Я должен отметить, что это часть приложения, работающего на ОС BlackBerry 10. Чтобы избежать создания и уничтожения QSqlQuery каждый раз, я также пытался вызвать query.clear () в конце flushBuffer (), но, похоже, он также удалил подготовленный SQL из экземпляра QSqlQuery (следующий вызов execBatch () не удался) ,
РЕДАКТИРОВАТЬ: я пытался избежать синтаксического анализа SQL каждый раз, поэтому я пытался сохранить неизменным m_setWithGeoQuery и просто скопировать его в flushBuffer ():
QSqlQuery query(m_setWithGeoQuery);
query.addBindValue(m_buffer.at(0));
...
Удивительно, но это не работает. Он ведет себя так же, как первый фрагмент.
Это ошибка в Qt: https://bugreports.qt.io/browse/QTBUG-43874.
Это происходит только при соблюдении обоих условий:
Как следствие, вы можете обойти эту ошибку, вызвав 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();
}
Других решений пока нет …