解决MySQL数据库多进程访问可能的冲突
一、问题出现
mysql数据库多进程访问可能冲突的地方:向数据库插入记录时,一般会先查当前最大编号maxNBBH,然后新记录的编号设置为(maxNBBH+1),然后执行插入操作。
使用事务操作可以一定程度上解决多进程访问数据库时的并发问题,但对于获取最大编号并在其基础上加一的操作,事务仍然可能存在一些问题。
在使用事务时,一般的步骤是:
- 开始事务
- 查询最大编号
- 在程序中计算新的编号(maxNBBH+1)
- 插入新记录
- 提交事务
然而,即便在事务中,如果多个进程同时开始执行这一系列步骤,可能会导致问题。以下是可能的情况:
-
并发读取: 多个进程同时执行“查询最大编号”这一步骤,可能得到相同的最大编号,从而导致后续插入的记录编号重复。
-
并发插入: 多个进程同时执行“插入新记录”这一步骤,由于它们都使用了相同的最大编号,可能导致插入的记录具有相同的编号。
二、问题解决
为了解决这些问题,需要在事务中使用适当的隔离级别,例如SERIALIZABLE
,以确保在一个事务中完成读取和插入操作。这样可以避免并发读取和并发插入引起的问题。
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
bool setTransactionIsolationLevel() {
// 建立数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("your_host");
db.setDatabaseName("your_database");
db.setUserName("your_user");
db.setPassword("your_password");
if (!db.open()) {
qDebug() << "Error: Unable to open database" << db.lastError();
return false;
}
// 设置事务隔离级别为SERIALIZABLE
QSqlQuery query("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", db);
if (!query.exec()) {
qDebug() << "Error: Unable to set transaction isolation level" << query.lastError();
db.close();
return false;
}
// 开始事务
if (!db.transaction()) {
qDebug() << "Error: Unable to start transaction" << db.lastError();
db.close();
return false;
}
// 进行其他数据库操作...
// 提交事务
if (!db.commit()) {
qDebug() << "Error: Unable to commit transaction" << db.lastError();
db.close();
return false;
}
// 关闭数据库连接
db.close();
return true;
}
设置事务的隔离级别可以在一定程度上解决多进程同时插入记录时可能导致的问题,尤其是解决并发读取和插入引起的问题。不同的隔离级别提供了不同的并发控制机制。在SERIALIZABLE
隔离级别下,事务之间是串行执行的,这意味着一个事务在另一个事务之前完成,从而避免了并发引起的问题。
解决QT不支持MySQL数据库事务的方案
转载链https://blog.csdn.net/qq_36553707/article/details/109852674
一、问题出现
QT 连接上数据库之后,开启了数据库事务。但是每次都return false;结果发现问题出在 db.transaction(), db.transaction() 返回值为false。
// 开始事务
if (!db.transaction()) {
qDebug() << "Error: Unable to start transaction" << db.lastError();
db.close();
return false;
}
二、发现问题
为了验证 QT 是否支持 MySQL 的数据库事务,添加了一下代码进行验证:
qDebug() << db.driver() -> hasFeature(QSqlDriver::Transactions);
结果发现 QT 不支持 MySQL 的数据库事务,在查阅了一系列资料后,最终锁定问题所在,是 MySQL 数据库的驱动和 QT 提供的数据库驱动不一致导致的。
三、解决方案
1、在 qt 的安装目录下打开以下文件夹:
2、双击 mysql.pro 文件打开该项目:
根据自己的配置选择,我的MSVC2017 32bit;如果后面编译不通过问题可能出在这里。
3、双击 mysql.pro 文件,进入配置文件:
4、对文件进行如下处理后,运行:
a. 将第 6 行代码注释掉:
# 用不上这个语句,不住是会报错,所以需要注释掉
# QMAKE_USE += mysql
b. 在第 1 行代码下添加以下代码:
这里有两种方式,我一开始用MySQL Server 8.0这个编译失败,后来重新安装的mysql-connector-c-6.1.11-win32.msi,使用的MySQL Connector C 6.1成功了。这里可以先使用MySQL Server 8.0试一下。
# 添加 MySQL 的 include 路径,这里按照自己的安装路径进行修改
#INCLUDEPATH +="C:\Program Files\MySQL\MySQL Server 8.0\include"
INCLUDEPATH +="C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include"
# 添加 MySQL 的 libmysql.lib 路径,为驱动的生成提供 lib 文件
#LIBS +="C:\Program Files\MySQL\MySQL Server 8.0\lib\libmysql.lib"
LIBS +="C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\lib\libmysql.lib"
c. 在文件末尾添加以下代码:
# 生成 dll 驱动文件的目录地址,这里将地址设置在 mysql 下的 lib 文件夹中
DESTDIR = ../mysql/lib/
d. 完成前面三步操作后,运行项目会出现一个对话弹框,点击 cannel 按钮取消即可:
如果编译失败,切换一下构建套件,可能是64bit的。
5、又在 qt 的安装目录下打开以下文件夹,发现会多出一个 lib 文件夹(该文件夹为pro配置中的指定文件生成文件夹,生成的驱动文件也在该文件夹中):
6、双击打开 lib 文件夹,会出现四个文件,复制被框选的两个文件:
7、在 qt 的安装目录下打开以下文件夹,将刚才复制的两个文件粘贴至该文件夹下,将原有的两个文件给覆盖掉:
8、再次运行之前写的项目,即可完美解决QT不支持MySQL数据库事务的问题。
注意:在 Qt5.11.3\5.11.3\msvc2015\lib 路径下的 libmysql.lib 文件与 Qt5.11.3\5.11.3\msvc2015\bin 路径下的 libmysql.dll 文件一定要和当前使用的 MySQL 数据库中包含的文件要匹配(即步骤 4.b 中 lib 路径下的两个文件),否则数据库能连上,但是无法支持数据库事务。(说明:对于 msvc2015
该文件夹名应当和当前开发环境对应)