From 8b243cd535a8654c1f5b47f0c1a5f7b438b837b9 Mon Sep 17 00:00:00 2001 From: duanshengchao <519970194@qq.com> Date: Mon, 17 Mar 2025 18:36:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0SQL=E8=AF=AD=E5=8F=A5?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E6=89=A7=E8=A1=8C=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/sqlQueryExecutor.h | 9 ++- source/sqlQueryExecutor.cpp | 136 +++++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 18 deletions(-) diff --git a/include/sqlQueryExecutor.h b/include/sqlQueryExecutor.h index 2ee9942..71f8871 100644 --- a/include/sqlQueryExecutor.h +++ b/include/sqlQueryExecutor.h @@ -12,8 +12,15 @@ class SqlQueryExecutor : public QObject public: static SqlQueryExecutor& instance(); - //基础SQL语句执行接口 + //单条SQL语句执行接口 QSqlQuery executeSQL(const QString& strConnectionName, const QString& strSQL, const QVariantHash& params = {}, bool useTranscation = false); + /** + * @brief 多条批量SQL语句执行接口 + * @param sqlStatements SQL语句列表 + * @param paramsList 参数列表(要与SQL语句一一对应) + */ + QSqlQuery executeBatchSQL(const QString& strConnectionName, const QStringList& sqlStatements, + const QList& paramsList = QList(), bool useTranscation = false); //基于具体业务的查询接口-对外调用 const QVector getModels(const QString&); const QVector getAttributeGroup(const QString&); diff --git a/source/sqlQueryExecutor.cpp b/source/sqlQueryExecutor.cpp index 4097089..c537ccc 100644 --- a/source/sqlQueryExecutor.cpp +++ b/source/sqlQueryExecutor.cpp @@ -15,7 +15,7 @@ SqlQueryExecutor::SqlQueryExecutor() SqlQueryExecutor::~SqlQueryExecutor() {} -//基础SQL语句执行接口 +//单条SQL语句执行接口 QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const QString& strSQL, const QVariantHash& params, bool useTranscation) { QSqlDatabase db = QSqlDatabase::database(strConnectionName); @@ -79,6 +79,84 @@ QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const Q return sqlQuery; } +//多条批量SQL语句执行接口 +QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, const QStringList& sqlStatements, const QList& paramsList, bool useTranscation) +{ + QSqlDatabase db = QSqlDatabase::database(strConnectionName); + if(!db.isOpen()) + { + LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(strConnectionName)); + throw DatabaseException(db.lastError()); + } + + //参数数量校验 + if(!paramsList.isEmpty() && sqlStatements.size() != paramsList.size()) + { + LOG_ERROR("SQL", QString("SQL statement does not match the number of parameters")); + throw DatabaseException(QSqlError("SQL statement does not match the number of parameters")); + } + + //事务 + bool transactionStarted = false; + if(useTranscation) + { + if(!db.transaction()) + { + LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText())); + throw DatabaseException(db.lastError()); + } + transactionStarted = true; + } + + QSqlQuery lastQuery(db); + try + { + for(int i = 0; i < sqlStatements.size(); i++) + { + const QString& strSQL = sqlStatements.at(i); + const QVariantHash& params = paramsList.isEmpty() ? QVariantHash() : paramsList.at(i); + + QSqlQuery sqlQuery(db); + if(!sqlQuery.prepare(strSQL)) + { + LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, sqlQuery.lastError().databaseText())); + throw DatabaseException(db.lastError()); + } + //绑定参数 + for(auto it = params.constBegin(); it != params.constEnd(); it++) + { + sqlQuery.bindValue(it.key(), it.value()); + } + if (!sqlQuery.exec()) + { + LOG_ERROR("SQL", QString("SQL '%1' execute error: %2").arg(strSQL, sqlQuery.lastError().databaseText())); + throw DatabaseException(sqlQuery.lastError()); + } + lastQuery = std::move(sqlQuery); + // 提交事务(如果已开启) + if(transactionStarted && !db.commit()) + { + throw DatabaseException(db.lastError()); + LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText())); + } + } + } + catch (const DatabaseException& e) + { + // 错误处理:回滚事务(如果已开启) + if(transactionStarted) + { + if(!db.rollback()) // 回滚失败时记录警告 + { + LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText())); + } + } + + throw; // 重新抛出异常 + } + + return lastQuery; +} //具体业务查询接口 const QVector SqlQueryExecutor::getModels(const QString& strConnectionName) @@ -126,6 +204,20 @@ QVector SqlQueryExecutor::getModelGroups(const QString& strConnectionName, bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model) { + //属于批量操作,需要开启事务,因为后续插入映射表时需要先插入进model_type记录的自增id,所以无法在一个接口函数中执行,所以事务放在在接口外部执行 + QSqlDatabase db = QSqlDatabase::database(connectionName); + if(!db.isOpen()) + { + LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName)); + return false; + } + + if(!db.transaction()) + { + LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); + return false; + } + int modelID = -1; //先向model_type中插入一条记录 QString strSQL = "INSERT INTO basic.model_type (model_type, model_name, remark) VALUES " @@ -134,8 +226,6 @@ bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model) params.insert(":type", model.type); params.insert(":name", model.name); params.insert(":remark", model.remark); - /*QString strSQL = "INSERT INTO basic.model_type (model_type, model_name, remark) VALUES (\'" + - model.type + "\',\'" + model.name + + "\',\'" + model.remark +"\')";*/ try { QSqlQuery query = executeSQL(connectionName, strSQL, params); @@ -144,30 +234,42 @@ bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model) } catch (const DatabaseException& e) { + if(!db.rollback()) // 回滚失败时记录警告 + { + LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); + } return false; } - //然后向model_group中插入记录 + //然后向model_group中插入记录,采用批量接口 + QStringList sqlStatements; + QList paramsList; for(int groupID : model.groups) { - /*strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES (" + - QString::number(modelID) + "," + QString::number(groupID) + ")";*/ - strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES " - "(:modelID, :groupID)"; + sqlStatements << "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES " + "(:modelID, :groupID)"; params.clear(); params.insert(":modelID", modelID); params.insert(":groupID", groupID); - try + paramsList << params; + } + try + { + executeBatchSQL(connectionName, sqlStatements, paramsList); + } + catch (const DatabaseException& e) + { + if(!db.rollback()) // 回滚失败时记录警告 { - executeSQL(connectionName, strSQL, params); - } - catch (const DatabaseException& e) - { - LOG_ERROR("SQL", QString::fromWCharArray(L"mapping model & group失败, modelID:%1, groupID:%2") - .arg(QString::number(modelID)) - .arg(QString::number(groupID))); - continue; + LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } + return false; + } + + if(!db.commit()) // 提交 + { + LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); + return false; } return true;