问题
就是为了多线程操作sqlite数据库,为什么,因为数据库是耗时的操作,一条数据的插入,差不多200ms,如果是数据插入多了,界面会有明显的卡顿,因此必须,多线程操作数据库。
问题是这样的:
插入数据之后,接着更新界面;然而,插入数据是比较耗时的操作,尤其插入数据多的情况下,这时,界面卡的就更为明显;让用户体验很不好。
多线程同步的概念:
即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,
而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。
就是一段代码段希望被保护起来,在执行过程中不能被其它线程打断,以保证计算结果的完整性,这就是线程同步的概念。
SQLite的多连接支持
SQLite支持从多个连接同时读写数据库。这意味着多个应用程序或同一个应用程序的多个实例可以同时存取同一个数据库文件。SQLite使用读/写锁定来控制数据库访问,以确保数据的一致性和完整性。
读操作:多个连接可以同时获得并保持共享锁(读锁),从而允许它们同时从数据库中读取数据。
写操作:写操作需要获得独占锁(写锁),这会阻塞其他读写操作,直到写操作完成并释放锁。因此,在同一时间内,SQLite只能支持一个写连接。
单连接与多连接并发对比
单连接:在单连接情况下,SQLite的性能通常很好,因为没有锁竞争的问题。但是,这限制了应用程序的并发能力。
多连接:多连接允许更高的并发性,但同时也带来了锁竞争和性能下降的风险。特别是在高并发环境下,写操作的性能可能会受到严重影响。
综合方案
综合上面的观点,我们就用了锁,锁的开销也不大,对写进行加写锁,写锁,就是保存所有连接只有一个可写;读加读锁,读锁,就是有写的时间,锁定,如果存在读或者无操作的情况下,就可以解锁。
解决过程
下面通过一个完整的例子,讲解这一个过程。
首先数据库操作,有增加、删除、查询等操作,除了这些常规数据库操作以外,还要加锁,就是为了防止写冲突,读写冲突,通过锁就解决了这些问题,想想,锁还是挺厉害的一个东西。
#pragma execution_character_set("utf-8")
#include "sqliteDb.h"
#include <QDebug>
#include <QCoreApplication>
#include <QThread>
#include <QDateTime>
QReadWriteLock SqliteDb::s_readWriteLock;
int SqliteDb::s_score = 0;
SqliteDb::SqliteDb(QObject *parent)
{
}
SqliteDb::~SqliteDb()
{
}
void SqliteDb::connectDb(QString &dbName)
{
// 创建并打开数据库连接
m_db = QSqlDatabase::addDatabase("QSQLITE", dbName);
m_db.setDatabaseName(QCoreApplication::applicationDirPath()+"/student.db");
if (!m_db.open()) {
qDebug() << "无法打开数据库!";
}
}
void SqliteDb::insertTableStudent(Student &student)
{
qDebug()<<"enter function insertTableStudent currentThreadId=" << QThread::currentThreadId()
<<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
QWriteLocker lock(&s_readWriteLock);
// 2. 创建QSqlQuery对象
QSqlQuery query(m_db);
// 3. 准备SQL语句
query.prepare("insert into student(seq, name, score) values(:seq, :name, :score);");
// 4. 绑定数据
query.bindValue(":seq", student.seq);
query.bindValue(":name", student.name);
query.bindValue(":score"