二 Qt之Sqlite数据库操作
想必用Qt做界面的同学都遇到过界面卡死的问题,这里我也遇到了,我的问题出在Sqlite数据库写处理的地方,可能您会说可以将数据库写处理的操作放在线程里执行啊。首先Sqlite数据库有这么一个不尽人意的特点,那就是它不支持在写数据的时候有别的操作参与进来,所以无论你将写操作放在自己创建的线程或是UI线程里都会有DB文件操作的风险。也许您会说在写数据操作时将DB连接锁起来,不让别的操作来用,或者是让别的操作等待。这样到底行不行呢?咱下面上代码: 首先说明:代码中有些变量或函数定义未给出,这里会给出它们的意思,旨在理解代码 //thread.h #ifndefTHREAD_H #defineTHREAD_H #include<QThread> classCThread:publicQThread { Q_OBJECT public: CThread(){} protected: voidrun(); }; #endif //类很简单 线程函数实现一: //thread.cpp #include"thread.h" #include"sqlTbl.h" externstd::vector<FILTERFILE>g_vecStaffInfo; voidCThread::run() { QSqlDatabasenSqlliteDB=QSqlDatabase::addDatabase(“QSQLITE”,“Connect”); nSqlliteDB.setDatabaseName("table.db"); nSqlliteDB.open(); if(!g_vecStaffInfo.empty()){ QSqlQueryQueryTbl(nSqlliteDB); QueryTbl.prepare("insertintotable(id,name,salary,age)values(?,?,?)"); std::vector<STAFFINFO>::iteratoritorStaff=g_vecStaffInfo.begin(); for(;itorStaff!=g_vecStaffInfo.end();itorStaff++) { intiId=itorStaff->id; QStringstrName=ToMultiChars(itorStaff->Name); intiSalary=itorStaff->salary; intiAge=itorStaff->age; QueryTbl.addBindValue(iId); QueryTbl.addBindValue(strName); QueryTbl.addBindValue(iSalary); QueryTbl.addBindValue(iAge); if(!QueryTbl.exec()) { QSqlErrorerror=QueryTbl.lastError(); QMessageBox::critical(0,"tableinsert",error.driverText(),QMessageBox::Ok); return; } } QSqlDatabase::database().commit(); QueryTbl.finish(); } } 其中g_vecStaffInfo是一个全局的数组,用来从上层传数据,然后通过线程将数据放进DB文件,ToMultiChars是将宽字节转为多字节的函数。 此时线程函数没有加锁,这个线程代码能不能满足不和界面查数据操作产生冲突呢,经验证产生冲突的事件是几率很高的偶发性事件。不知大家知不知道原因所在。 线程函数实现二: #include"thread.h" #include"sqlTbl.h" externstd::vector<FILTERFILE>g_vecStaffInfo; externQMutexg_nSqlMutex; voidCThread::run() { QSqlDatabasenSqlliteDB=QSqlDatabase::addDatabase(“QSQLITE”,“Connect”); nSqlliteDB.setDatabaseName("table.db"); nSqlliteDB.open(); if(!g_vecStaffInfo.empty()){ if(g_nSqlMutex.tryLock()) g_nSqlMutex.unlock(); g_nSqlMutex.lock(); QSqlQueryQueryTbl(nSqlliteDB); QueryTbl.prepare("insertintotable(id,QMessageBox::Ok); return; } } QSqlDatabase::database().commit(); g_nSqlMutex.unlock(); QueryTbl.finish(); } } 线程函数实现二行不行呢,这里认为QueryTbl对nSqlliteDB是独占的,经测试这样是解决了DB文件访问冲突的问题,但是原始问题还是没有被解决:界面访问数据时卡死。 线程函数实现三: #include"thread.h" #include"sqlTbl.h" externstd::vector<FILTERFILE>g_vecStaffInfo; externQMutexg_nSqlMutex; voidCThread::run() { QSqlDatabasenSqlliteDB=QSqlDatabase::addDatabase(“QSQLITE”,“Connect”); nSqlliteDB.setDatabaseName("table.db"); nSqlliteDB.open(); if(!g_vecStaffInfo.empty()){ if(g_nSqlMutex.tryLock()) g_nSqlMutex.unlock(); else return; QSqlQueryQueryTbl(nSqlliteDB); nSqlliteDB.transaction(); QueryTbl.prepare("insertintotable(id,QMessageBox::Ok); return; } } g_nSqlMutex.lock(); nSqlliteDB.commit(); g_nSqlMutex.unlock(); QueryTbl.finish(); } } 线程函数实现三同样增加了互斥,但有些不同的是,这里用到了Sqlite数据库的事务,代码增加了nSqlliteDB.transaction();为什么这样呢,经过网上查找,写DB文件,像实现一和二每进行一次QueryTbl.exec()都会对DB文件进行打开和关闭操作一次,相当于写10000条数据打开关闭10000次,这样的写速度真是能把我们搞疯掉;而增加事务后就不同了,写10000条数据,只会在commit的时候打开关闭一次,这样的速率提升不言而喻。在commit的地方加锁,锁占的时间也在所能接受的范围之内。 这样暂时将我的问题解决了,不知道是否能给各位同行带来帮助,如果有何欠妥的地方,忘多多指教。若能给大家提供帮助,我将甚感荣幸。 转载请注明:http://blog.csdn.net/fanbiqi/article/details/40212917 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |