最近在写的一个数据采集的软件,需要多线程访问数据库。恰好因为某些原因,我用的是sqlite这样比较轻量级的数据库。在使用中碰到了不少麻烦。现在来记录以下。
1、多线程时一定要注意访问接口名称的区分
所谓的访问接口的名称,以我的项目举例,就是:
QString sqlName="test";
QSqlDatabase *db=new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE",sqlName));
上面那个sqlName,就是访问接口的名称,如果你要多个线程访问,一定会在每个线程中都创建一个QSqlDatabase,因为在一个线程中创建的QSqlDatabase,只能用在那个线程中,不能跨线程使用。因此,生成多个线程中的多个QSqlDatabase,一定要注意这个接口的名称,一定要不同,不然很容易出现软件崩溃。
2、sqlite的并发实现
如果只是对sqlite有查询操作,其实并没有什么难点,如果有写入操作,其实sqlite自身好像带有一个循环排队插入的机制,已经具备一定的并发能力。
不过我为了稳妥起见,用了线程锁,保证我插入数据库的那一段代码只能在一个线程中运行,当别的线程要调用时,先排队。
QMutex mutex;
mutex.lock;
mutex.unlock;
3、sqlite中学会使用事务操作
因为sqlite是一个轻量级的数据库,所以在增删改,以及查询操作上,可能会消耗更多的时间,这个时候就可能会出现过于繁忙,导致线程崩溃,以至于软件崩溃。因此,在使用for或者别的循环语句插入较多的形式单一的内容时,一定要多使用事务操作,减少sqlite处理的压力和时间,这样会减少出问题的概率。
QSqlDatabase *db=new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE",sqlName));
QSqlQuery query(*db);
db->transaction();
query.exec("insert XXXXXXXX");
db->commit();
4、当数据表较大时,查询时尽量不要查询所有数据
当数据表已经很大了,而你又想要查看一下最近插入的数据,并且显示,这个时候,如果还有别的线程在进行写入操作,如果你查询很大的数据量,也可能会导致软件崩溃。因此,利用limit进行限制。
QSqlQueryModel *model;
QString strString=QString("select * from %1 order by ID desc limit %2).arg("tableName").arg("100");
model->setQuery(strString,*db);
ui->tableview->setModel(model);
总结
sqlite确实很方便,但是也确实因为方便,也会带来很多麻烦,所以很多时候要想方设法的给sqlite减负,这样使用起来,会畅通很多。