注意:
1.MySql是可以实现并发数据读写的,Sqlite则不支持。
2.Sqlite多线程下读写要么在每个子线程加线程锁互斥,要么将读写只放到一个线程处理。
3.Mysql多线程下读写最方便的就是创建一个数据库操作类,然后每个数据库操作类对象创建一些槽函数用来处理数据库读写业务逻辑,再创建一个信号发射类,将信号发射类的一些业务信号于数据库处理类槽函数进行信号槽连接。这样每创建一个数据库操作类就再对应创建一个信号发射类,将其与信号发射类相关信号槽连接,再创建一个QThread,然后QThread::start后,再用信号发射类对象发射就可以实现多个子线程对mysql进行并发读写操作了。
4.每个子线程只操作自己数据库连接,所以要注意数据库的连接及绑定还有执行语句所绑定的连接。(数据库连接名,执行语句所绑定的连接名等要对应好),具体如下
QSqlDatabase::addDatabase第二个参数名称要不一致
QSqlDatabase::addDatabase和QSqlDatabase::open外围加锁,保证连接时不会造成数据竞争(Qt 动态加载plugin, 加载 plugin 的部分,涉及到对本地库文件的管理,出现了数据竞争)。
QSqlQuery(QSqlDatabase) 强制指定连接
连接使用完后记得删除QSqlDatabase::removeDatabase。
/*************************************mysql数据库多线程写入 多线程操作mysql
步骤:
1、QSqlDatabase::addDatabase第二个参数名称要不一致。
2、QSqlDatabase::addDatabase和QSqlDatabase::open外围加锁,保证连接时不会造成数据竞争(Qt 动态加载plugin, 加载 plugin 的部分,涉及到对本地库文件的管理,出现了数据竞争)。
3、QSqlQuery(QSqlDatabase) 强制指定连接
4、连接使用完后记得删除QSqlDatabase::removeDatabase。
经过代码测试,Qt可以对mysql多线程操作。
1 void T1::Run()
2 {
3 QSqlDatabase db;
4 mutex_->lock();
5 if(QSqlDatabase::contains("zk1"))
6 db = QSqlDatabase::database("QMYSQL", "zk1");
7 else{
8 db = QSqlDatabase::addDatabase("QMYSQL", "zk1");
9 db.setHostName("127.0.0.1");
10 db.setPort(3306);
11 db.setUserName("root");
12 db.setPassword("zhaokai");
13 db.setDatabaseName("t1");
14 }
15
16 qDebug()<<QSqlDatabase::connectionNames();
17
18 if(!db.open())
19 qDebug()<<"T1 warning!";
20 mutex_->unlock();
21 QSqlQuery query(db);
22
23 QElapsedTimer timer;
24 timer.start();
25 int count = 0;
26 db.transaction();
27 while(count<10){
28 QString sql = "INSERT INTO pwtest VALUES(AES_ENCRYPT('%1','zhaokai'), AES_ENCRYPT('T1','zhaokai'));";
29 sql = sql.arg(QString::number(count));
30 query.exec(sql);
31 count++;
32 QThread::msleep(1); // 加了1ms延时,保证数据乱序
33 qDebug()<<"t1 count = "<<count;
34 }
35 db.commit();
36 }
1 void T2::Run()
2 {
3 QSqlDatabase db;
4 mutex_->lock();
5 if(QSqlDatabase::contains("zk2"))
6 db = QSqlDatabase::database("QMYSQL", "zk2");
7 else{
8 db = QSqlDatabase::addDatabase("QMYSQL", "zk2");
9 db.setHostName("127.0.0.1");
10 db.setPort(3306);
11 db.setUserName("root");
12 db.setPassword("zhaokai");
13 db.setDatabaseName("t1");
14 }
15 if(!db.open())
16 qDebug()<<"T2 warning!";
17 mutex_->unlock();
18 QSqlQuery query(db);
19
20 query.exec("START TRANSACTION");
21 int count = 0;
22 while(count<10){
23 QString sql = "INSERT INTO pwtest VALUES(AES_ENCRYPT('%1','zhaokai'), AES_ENCRYPT('T2','zhaokai'));";
24 sql = sql.arg(QString::number(count));
25 query.exec(sql);
26 count++;
27 qDebug()<<"t2 count = "<<count;
28 }
29 query.exec("COMMIT");
30 }
/***********************************Qt mysql多线程并发读写
Qt MySQL多线程并发读写
在软件开发中,对于需要与数据库进行交互的应用程序,多线程并发读写数据库是一项常见的需求。Qt作为一个跨平台的C++图形用户界面应用程序开发框架,提供了丰富的功能和组件来方便开发者进行数据库操作。本文将介绍如何在Qt中实现多线程并发读写MySQL数据库,并提供相应的代码示例。
前期准备
在进行多线程并发读写MySQL数据库之前,需要安装Qt和MySQL数据库,并确保Qt中已经集成了相应的数据库插件。在Qt中,可以通过Qt SQL模块来进行数据库操作,它支持多种数据库,包括MySQL。
实现多线程并发读写
在Qt中,可以使用QSqlDatabase类来连接MySQL数据库,并通过QSqlQuery类来执行SQL查询。为了实现多线程并发读写,可以使用Qt中的QThread类来创建线程,并在每个线程中进行数据库操作。
连接MySQL数据库
首先需要在Qt中连接MySQL数据库,可以通过以下方式:
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("mydatabase");
db.setUserName("root");
db.setPassword("password");
bool ok = db.open();
if (ok) {
qDebug() << "Database connected successfully!";
} else {
qDebug() << "Database connection failed!";
}
实现多线程
接下来,可以通过创建多个QThread实例来实现多线程并发读写数据库。每个线程可以执行不同的数据库操作,如读取数据、插入数据等。以下是一个简单的多线程示例:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork()
{
QSqlQuery query;
query.exec("SELECT * FROM mytable");
while (query.next()) {
// Read data from database
}
// Insert data into database
query.prepare("INSERT INTO mytable (name, age) VALUES (:name, :age)");
query.bindValue(":name", "John");
query.bindValue(":age", 30);
query.exec();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Worker worker1, worker2;
QThread thread1, thread2;
worker1.moveToThread(&thread1);
worker2.moveToThread(&thread2);
QObject::connect(&thread1, &QThread::started, &worker1, &Worker::doWork);
QObject::connect(&thread2, &QThread::started, &worker2, &Worker::doWork);
thread1.start();
thread2.start();
return app.exec();
}
在上面的示例中,创建了两个Worker对象并将其移动到不同的线程中,然后分别执行数据库操作。通过将不同的数据库操作放在不同的线程中,可以实现并发读写数据库。
序列图示例
下面是一个使用mermaid语法中的sequenceDiagram标识的序列图,展示了两个线程并发读写MySQL数据库的交互过程:
Database
Thread2
Thread1
Database
Thread2
Thread1
读取数据
返回数据
插入数据
插入成功
甘特图示例
下面是一个使用mermaid语法中的gantt标识的甘特图,展示了两个线程对数据库的读写操作的时间分布情况:
2022-07-01
2022-07-01
2022-07-02
2022-07-02
2022-07-02
2022-07-02
2022-07-03
2022-07-03
2022-07-03
2022-07-03
2022-07-04
2022-07-04
读取数据
插入数据
线程1
线程2
多线程并发读写数据库甘特图
结语
通过本文的介绍,我们了解了如何在Qt中实现多线程并发读写MySQL数据库。通过创建多个线程并对数据库进行不同的操作,可以提高数据库操作的效率和并发能力。在实际开发中,需要根据具体的需求和场景来设计和优化多线程并发读写数据库的方案,以确保数据的一致性和稳定
/********************************QT数据库连接初始化和删除的方法
从网上查了很多资料,大多只是简单的说一下,没有详细的说明。后来又认真看了一下QT助手资料,写一数据库连接的详细用法。不多说,看以下代码就明白了。
QString connect = "connectname"; //自定义的连接名称
{ //这个括号一定要有,这样可以把QSqlDatabase约束在一个指定的作用域范围内
QSqlDatabase data;
initDateBase(data, connect);
const QString time = PatternImgMs::getTimeString();
const QString str = sqlstring; //自定义的SQL处理
QSqlQuery query(data);
if (!query.exec(str))
{
qDebug() << "Error: Fail to insert data. ";
}
data.close();
}
//在作用域范围外再删除以这个名称命名的数据库连接
QSqlDatabase::removeDatabase(connect);
void initDateBase(QSqlDatabase& data, QString& connectName)
{
if (QSqlDatabase::contains(connectName))
{
///不允许创建两个相同名字的连接,所以首先判断是否存在相同的连接
data = QSqlDatabase::database(connectName);
}
else
{
///创建新的连接
data = QSqlDatabase::addDatabase("QSQLITE", connectName);
data.setDatabaseName("database.db");
if (!data.open())
{
//QMessageBox::critical(nullptr, "错误", "数据库连接错误!");
exit(0);
}
}
}