二 Qt之Sqlite数据库操作
来源:互联网 发布:炉石传说 橙卡 知乎 编辑:程序博客网 时间:2024/05/14 01:32
想必用Qt做界面的同学都遇到过界面卡死的问题,这里我也遇到了,我的问题出在Sqlite数据库写处理的地方,可能您会说可以将数据库写处理的操作放在线程里执行啊。首先Sqlite数据库有这么一个不尽人意的特点,那就是它不支持在写数据的时候有别的操作参与进来,所以无论你将写操作放在自己创建的线程或是UI线程里都会有DB文件操作的风险。也许您会说在写数据操作时将DB连接锁起来,不让别的操作来用,或者是让别的操作等待。这样到底行不行呢?咱下面上代码:
首先说明:代码中有些变量或函数定义未给出,这里会给出它们的意思,旨在理解代码
//thread.h
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
class CThread : public QThread
{
Q_OBJECT
public:
CThread(){}
protected:
void run();
};
#endif
//类很简单
线程函数实现一:
//thread.cpp
#include "thread.h"
#include "sqlTbl.h"
extern std::vector<FILTERFILE> g_vecStaffInfo;
void CThread::run()
{
QSqlDatabase nSqlliteDB = QSqlDatabase::addDatabase( “QSQLITE”, “Connect” );
nSqlliteDB.setDatabaseName( "table.db" );
nSqlliteDB.open();
if( !g_vecStaffInfo.empty() ){
QSqlQuery QueryTbl(nSqlliteDB);
QueryTbl.prepare( "insert into table( id, name,salary, age ) values( ?, ?, ?, ?)" );
std::vector<STAFFINFO>::iterator itorStaff = g_vecStaffInfo.begin();
for( ; itorStaff != g_vecStaffInfo.end(); itorStaff++ )
{
int iId = itorStaff->id;
QString strName = ToMultiChars( itorStaff->Name );
int iSalary = itorStaff->salary;
int iAge = itorStaff->age;
QueryTbl.addBindValue( iId );
QueryTbl.addBindValue( strName );
QueryTbl.addBindValue( iSalary );
QueryTbl.addBindValue( iAge );
if( !QueryTbl.exec() )
{
QSqlError error = QueryTbl.lastError();
QMessageBox::critical(0, "table insert", error.driverText(), QMessageBox::Ok);
return;
}
}
QSqlDatabase::database().commit();
QueryTbl.finish();
}
}
其中g_vecStaffInfo是一个全局的数组,用来从上层传数据,然后通过线程将数据放进DB文件,ToMultiChars是将宽字节转为多字节的函数。
此时线程函数没有加锁,这个线程代码能不能满足不和界面查数据操作产生冲突呢,经验证产生冲突的事件是几率很高的偶发性事件。不知大家知不知道原因所在。
线程函数实现二:
#include "thread.h"
#include "sqlTbl.h"
extern std::vector<FILTERFILE> g_vecStaffInfo;
extern QMutex g_nSqlMutex;
void CThread::run()
{
QSqlDatabase nSqlliteDB = QSqlDatabase::addDatabase( “QSQLITE”, “Connect” );
nSqlliteDB.setDatabaseName( "table.db" );
nSqlliteDB.open();
if( !g_vecStaffInfo.empty() ){
if( g_nSqlMutex.tryLock() )
g_nSqlMutex.unlock();
g_nSqlMutex.lock();
QSqlQuery QueryTbl(nSqlliteDB);
QueryTbl.prepare( "insert into table( id, name,salary, age ) values( ?, ?, ?, ?)" );
std::vector<STAFFINFO>::iterator itorStaff = g_vecStaffInfo.begin();
for( ; itorStaff != g_vecStaffInfo.end(); itorStaff++ )
{
int iId = itorStaff->id;
QString strName = ToMultiChars( itorStaff->Name );
int iSalary = itorStaff->salary;
int iAge = itorStaff->age;
QueryTbl.addBindValue( iId );
QueryTbl.addBindValue( strName );
QueryTbl.addBindValue( iSalary );
QueryTbl.addBindValue( iAge );
if( !QueryTbl.exec() )
{
QSqlError error = QueryTbl.lastError();
QMessageBox::critical(0, "table insert", error.driverText(), QMessageBox::Ok);
return;
}
}
QSqlDatabase::database().commit();
g_nSqlMutex.unlock();
QueryTbl.finish();
}
}
线程函数实现二行不行呢,这里认为QueryTbl对nSqlliteDB是独占的,经测试这样是解决了DB文件访问冲突的问题,但是原始问题还是没有被解决:界面访问数据时卡死。
线程函数实现三:
#include "thread.h"
#include "sqlTbl.h"
extern std::vector<FILTERFILE> g_vecStaffInfo;
extern QMutex g_nSqlMutex;
void CThread::run()
{
QSqlDatabase nSqlliteDB = QSqlDatabase::addDatabase( “QSQLITE”, “Connect” );
nSqlliteDB.setDatabaseName( "table.db" );
nSqlliteDB.open();
if( !g_vecStaffInfo.empty() ){
if( g_nSqlMutex.tryLock() )
g_nSqlMutex.unlock();
else
return;
QSqlQuery QueryTbl(nSqlliteDB);
nSqlliteDB.transaction();
QueryTbl.prepare( "insert into table( id, name,salary, age ) values( ?, ?, ?, ?)" );
std::vector<STAFFINFO>::iterator itorStaff = g_vecStaffInfo.begin();
for( ; itorStaff != g_vecStaffInfo.end(); itorStaff++ )
{
int iId = itorStaff->id;
QString strName = ToMultiChars( itorStaff->Name );
int iSalary = itorStaff->salary;
int iAge = itorStaff->age;
QueryTbl.addBindValue( iId );
QueryTbl.addBindValue( strName );
QueryTbl.addBindValue( iSalary );
QueryTbl.addBindValue( iAge );
if( !QueryTbl.exec() )
{
QSqlError error = QueryTbl.lastError();
QMessageBox::critical(0, "table insert", error.driverText(), 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
- 二 Qt之Sqlite数据库操作
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)实例
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)
- Qt之操作数据库(SQLite)实例
- Qt之操作数据库(SQLite)实例
- Qt操作SQLite数据库
- QT 操作Sqlite数据库
- QT操作Sqlite数据库
- qt操作sqlite数据库
- Qt SQLite数据库操作
- qt sqlite数据库操作
- 使用mingw在eclipse运行c++程序
- C语言第三天
- Android环境下通过SOCKET传递Parcel包并解出数据的例子
- Matlab数据处理
- Java程序优化策略整理
- 二 Qt之Sqlite数据库操作
- 面试二三事
- hibernate关联映射
- 阿里2015校招面试回忆录(成功拿到offer)
- 汽车报价大全IOS客户端
- 快速构建网站之前言
- 另类解读C语言数组的特性
- jQuery中利用JSONP解决AJAX跨域问题
- hibernate查询,生命周期