300 lines
8.5 KiB
C++
300 lines
8.5 KiB
C++
#include "sqliteread.h"
|
||
#include <QtConcurrent>
|
||
SQLiteReadWrite::SQLiteReadWrite(QObject *parent)
|
||
: QObject(parent)
|
||
{
|
||
m_connectionName = QString("SQLiteConnection_%1").arg(reinterpret_cast<quintptr>(this));
|
||
idValue = 0;
|
||
m_stopRequested = false;
|
||
|
||
}
|
||
|
||
SQLiteReadWrite::~SQLiteReadWrite()
|
||
{
|
||
if (!m_isClosed) {
|
||
closeDatabase();
|
||
}
|
||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||
|
||
}
|
||
|
||
bool SQLiteReadWrite::openDatabase(const QString &dbPath)
|
||
{
|
||
QMutexLocker locker(&m_mutex);
|
||
|
||
if (!m_isClosed) {
|
||
closeDatabase();
|
||
}
|
||
|
||
// 确定数据库路径
|
||
QString path = dbPath;
|
||
if (path.isEmpty()) {
|
||
QString appDir = QCoreApplication::applicationDirPath();
|
||
path = QDir(appDir).filePath("test_readwrite.db");
|
||
}
|
||
|
||
m_dbPath = path;
|
||
|
||
// 打开数据库
|
||
m_database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
|
||
m_database.setDatabaseName(m_dbPath);
|
||
|
||
if (!m_database.open()) {
|
||
log(QString("打开数据库失败: %1").arg(m_database.lastError().text()));
|
||
return false;
|
||
}
|
||
|
||
// 启用外键和WAL模式(提高并发性能)
|
||
QSqlQuery query(m_database);
|
||
// 开启外键约束
|
||
if (!query.exec("PRAGMA foreign_keys = ON;")) {
|
||
log(QString("启用外键失败: %1").arg(query.lastError().text()));
|
||
}
|
||
|
||
// 开启WAL模式(写时复制,提高读写并发性能)
|
||
if (!query.exec("PRAGMA journal_mode = WAL;")) {
|
||
log(QString("启用WAL模式失败: %1").arg(query.lastError().text()));
|
||
}
|
||
|
||
// // 设置同步模式(在安全性和性能之间权衡)
|
||
// if (!query.exec("PRAGMA synchronous = NORMAL;")) {
|
||
// log(QString("设置同步模式失败: %1").arg(query.lastError().text()));
|
||
// }
|
||
|
||
// 设置缓存大小
|
||
if (!query.exec("PRAGMA cache_size = 10000;")) {
|
||
log(QString("设置缓存大小失败: %1").arg(query.lastError().text()));
|
||
}
|
||
|
||
m_isClosed = false;
|
||
log(QString("数据库打开成功: %1").arg(m_dbPath));
|
||
return true;
|
||
}
|
||
|
||
void SQLiteReadWrite::closeDatabase()
|
||
{
|
||
QMutexLocker locker(&m_mutex);
|
||
|
||
if (m_isClosed) {
|
||
return;
|
||
}
|
||
m_isClosed = true;
|
||
|
||
if (m_database.isOpen()) {
|
||
m_database.close();
|
||
log("数据库已关闭");
|
||
}
|
||
if (QSqlDatabase::contains(m_connectionName)) {
|
||
QSqlDatabase::removeDatabase(m_connectionName);
|
||
}
|
||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||
}
|
||
|
||
|
||
void SQLiteReadWrite::startReadWriteOperation()
|
||
{
|
||
if (!m_database.isOpen()) {
|
||
emit operationCompleted(false, "数据库未打开");
|
||
return;
|
||
}
|
||
|
||
m_stopRequested = false;
|
||
//在单独的线程中执行,避免阻塞UI
|
||
QtConcurrent::run(this, &SQLiteReadWrite::processReadWrite);
|
||
}
|
||
|
||
void SQLiteReadWrite::stopOperation()
|
||
{
|
||
m_stopRequested = true;
|
||
log("stop requese send");
|
||
}
|
||
|
||
void SQLiteReadWrite::processReadWrite()
|
||
{
|
||
m_timer.start();
|
||
log("开始边读边写操作...");
|
||
try {
|
||
processWithMultipleConnections();
|
||
if (!m_stopRequested) {
|
||
qint64 elapsed = m_timer.elapsed();
|
||
QString message = QString("操作完成,总耗时: %1 毫秒").arg(elapsed);
|
||
log(message);
|
||
emit operationCompleted(true, message);
|
||
} else {
|
||
emit operationCompleted(false, "quxiao");
|
||
}
|
||
|
||
} catch (const std::exception &e) {
|
||
log(QString("发生异常: %1").arg(e.what()));
|
||
emit operationCompleted(false, QString("异常: %1").arg(e.what()));
|
||
}
|
||
}
|
||
|
||
|
||
void SQLiteReadWrite::processWithMultipleConnections()
|
||
{
|
||
const QString readConnName = m_connectionName + "_read";
|
||
|
||
int totalRecords = 0;
|
||
int processedRecords = 0;
|
||
bool readSuccess = false;
|
||
|
||
{
|
||
QSqlDatabase readDb = QSqlDatabase::addDatabase("QSQLITE", readConnName);
|
||
readDb.setDatabaseName(m_dbPath);
|
||
|
||
if (!readDb.open()) {
|
||
QString logMsg = QString("打开读取连接失败: %1").arg(readDb.lastError().text());
|
||
log(logMsg.toUtf8().constData());
|
||
emit operationCompleted(false, "无法打开数据库连接");
|
||
return;
|
||
}
|
||
|
||
{
|
||
QSqlQuery optimizeQuery(readDb);
|
||
optimizeQuery.exec("PRAGMA journal_mode = WAL;");
|
||
optimizeQuery.exec("PRAGMA synchronous = OFF;");
|
||
optimizeQuery.exec("PRAGMA cache_size = -200000;"); // 200MB缓存
|
||
optimizeQuery.exec("PRAGMA temp_store = MEMORY;");
|
||
optimizeQuery.exec("PRAGMA mmap_size = 2147483648;"); // 2GB内存映射
|
||
optimizeQuery.exec("PRAGMA query_only = ON;");
|
||
optimizeQuery.finish();
|
||
}
|
||
|
||
{
|
||
QSqlQuery countQuery(readDb);
|
||
if (countQuery.exec("SELECT COUNT(*) FROM lmdatainfov2")) {
|
||
countQuery.next();
|
||
totalRecords = countQuery.value(0).toInt();
|
||
}
|
||
countQuery.finish();
|
||
}
|
||
|
||
if (totalRecords == 0) {
|
||
log("数据库中无记录");
|
||
readDb.close();
|
||
emit operationCompleted(false, "数据库中无有效数据");
|
||
return;
|
||
}
|
||
|
||
QString totalMsg = QString("GVF数据库总记录数: %1 条").arg(totalRecords);
|
||
log(totalMsg.toUtf8().constData());
|
||
|
||
const int pageSize = 200;
|
||
int lastId = 0;
|
||
|
||
m_DataBaseList.clear();
|
||
m_DataBaseList.reserve(totalRecords);
|
||
|
||
while (!m_stopRequested) {
|
||
QSqlQuery readQuery(readDb);
|
||
readQuery.setForwardOnly(true);
|
||
readQuery.prepare("SELECT id, data FROM lmdatainfov2 WHERE id > :lastId ORDER BY id LIMIT :limit");
|
||
readQuery.bindValue(":lastId", lastId);
|
||
readQuery.bindValue(":limit", pageSize);
|
||
|
||
if (!readQuery.exec()) {
|
||
QString errMsg = QString("数据读取失败: %1").arg(readQuery.lastError().text());
|
||
log(errMsg.toUtf8().constData());
|
||
readQuery.finish();
|
||
break;
|
||
}
|
||
|
||
int pageRecords = 0;
|
||
while (readQuery.next() && !m_stopRequested) {
|
||
DataBaseStruct data;
|
||
data.id = readQuery.value(0).toInt();
|
||
data.data = readQuery.value(1).toByteArray();
|
||
m_DataBaseList.append(data);
|
||
lastId = data.id;
|
||
pageRecords++;
|
||
}
|
||
|
||
readQuery.finish();
|
||
readQuery.clear();
|
||
|
||
if (pageRecords == 0) {
|
||
break;
|
||
}
|
||
|
||
processedRecords += pageRecords;
|
||
int remainingRecords = totalRecords - processedRecords;
|
||
int progress = (processedRecords * 100) / totalRecords;
|
||
emit progressUpdated(progress, processedRecords, totalRecords);
|
||
}
|
||
|
||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||
readDb.close();
|
||
readSuccess = true;
|
||
}
|
||
|
||
QThread::msleep(50);
|
||
|
||
if (QSqlDatabase::contains(readConnName)) {
|
||
QSqlDatabase::removeDatabase(readConnName);
|
||
}
|
||
|
||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||
}
|
||
|
||
|
||
|
||
QSqlDatabase SQLiteReadWrite::createConnection()
|
||
{
|
||
QString connName = QString("TempConnection_%1_%2")
|
||
.arg(m_connectionName)
|
||
.arg(QDateTime::currentMSecsSinceEpoch());
|
||
|
||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connName);
|
||
db.setDatabaseName(m_dbPath);
|
||
|
||
if (!db.open()) {
|
||
log(QString("创建临时连接失败: %1").arg(db.lastError().text()));
|
||
}
|
||
|
||
return db;
|
||
}
|
||
|
||
|
||
void SQLiteReadWrite::log(const QString &message)
|
||
{
|
||
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||
QString logMsg = QString("[%1] %2").arg(timestamp).arg(message);
|
||
|
||
emit logMessage(logMsg);
|
||
}
|
||
|
||
QVector<DataBaseStruct> SQLiteReadWrite::DataBaseList() const
|
||
{
|
||
QMutexLocker locker(&m_mutex);
|
||
return m_DataBaseList;
|
||
}
|
||
|
||
QString SQLiteReadWrite::getMeasureStartTime()
|
||
{
|
||
QMutexLocker locker(&m_mutex);
|
||
if (m_isClosed || !m_database.isOpen())
|
||
{
|
||
log("Database not open, cannot read statistic starttime");
|
||
return "";
|
||
}
|
||
QSqlQuery query(m_database);
|
||
// lmstatisticinfov2 存储本次测量标准起止时间
|
||
if (!query.exec("SELECT starttime FROM lmstatisticinfov2 LIMIT 1;"))
|
||
{
|
||
log(QString("Query lmstatisticinfov2 failed: %1").arg(query.lastError().text()));
|
||
return "";
|
||
}
|
||
if (query.next())
|
||
{
|
||
return query.value("starttime").toString();
|
||
}
|
||
log("lmstatisticinfov2 table has no starttime record");
|
||
return "";
|
||
}
|
||
|
||
void SQLiteReadWrite::setIdValue(int value)
|
||
{
|
||
idValue = value;
|
||
}
|