#include "global.h" #include "sqlQueryExecutor.h" #include "logger.h" #include #include SqlQueryExecutor& SqlQueryExecutor::instance() { //采用静态局部变量的方式,静态局部变量的初始化是在第一次访问时,以后的调用不会多次初始化,并且生命周期和程序一致 static SqlQueryExecutor instance; return instance; } SqlQueryExecutor::SqlQueryExecutor() {} SqlQueryExecutor::~SqlQueryExecutor() {} //单条SQL语句执行接口 QSqlQuery SqlQueryExecutor::executeSQL(const QString& connectionName, const QString& strSQL, const QVariantHash& params, bool useTranscation) { QSqlDatabase db = QSqlDatabase::database(connectionName); if(!db.isOpen()) { LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName)); throw DatabaseException(db.lastError()); } //事务 bool transactionStarted = false; if(useTranscation) { if(!db.transaction()) { LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); throw DatabaseException(db.lastError()); } transactionStarted = true; } QSqlQuery sqlQuery(db); try { 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()); } // 提交事务(如果已开启) if(transactionStarted && !db.commit()) { throw DatabaseException(db.lastError()); LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } } catch (const DatabaseException& e) { // 错误处理:回滚事务(如果已开启) if(transactionStarted) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚失败时记录警告 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } } throw; // 重新抛出异常 } return sqlQuery; } //多条批量SQL语句执行接口 QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& connectionName, const QStringList& sqlStatements, const QList& paramsList, bool useTranscation) { QSqlDatabase db = QSqlDatabase::database(connectionName); if(!db.isOpen()) { LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName)); 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(connectionName, 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(connectionName, db.lastError().databaseText())); } } catch (const DatabaseException& e) { // 错误处理:回滚事务(如果已开启) if(transactionStarted) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚失败时记录警告 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } } throw; // 重新抛出异常 } return lastQuery; } //获取表的字段类型信息(目前只针对PostgerSQL) QHash SqlQueryExecutor::getFiledType(const QString& connectionName, const QString& table, const QString& schema) { QHash fieldTypes; QString strSQL = QString( "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod) " "FROM pg_catalog.pg_attribute a " "JOIN pg_catalog.pg_class c ON a.attrelid = c.oid " "JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid " "WHERE c.relname = LOWER(:table_name) " "AND n.nspname = LOWER(:schema_name) " "AND a.attnum > 0 AND NOT a.attisdropped;" ); QVariantHash params; params.insert(":table_name", table); params.insert(":schema_name", schema); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); while(query.next()) fieldTypes.insert(query.value(0).toString(), query.value(1).toString()); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性原始数据类型失败")); } return fieldTypes; } //具体业务查询接口 const QVector SqlQueryExecutor::getModels(const QString& connectionName) { QVector models; QString strSQL = "SELECT id, model_type, model_name, remark FROM basic.model_type ORDER BY id ASC"; try { QSqlQuery query = executeSQL(connectionName, strSQL); while(query.next()) { int id = query.value(0).toInt(); QString type = query.value(1).toString(); QString name = query.value(2).toString(); QString remark = query.value(3).toString(); QVector groups = getModelGroups(connectionName, id); models.emplace_back(id, name, type, remark, groups); } } catch (const DatabaseException& e) { emit errorOccurred(QString::fromWCharArray(L"获取模型信息失败,详情可见日志文件")); } return models; //编译器的RVO/NRVO会自动优化、避免临时拷贝 } int SqlQueryExecutor::getModelCount(const QString& connectionName) { int count = 0; QString strSQL = QString("SELECT COUNT(*) FROM basic.model_type"); try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) count = query.value(0).toInt(); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取模型数量失败")); } return count; } QVector SqlQueryExecutor::getModelGroups(const QString& connectionName, int modelID) { QVector groups; QString strSQL = "SELECT attribute_group_id FROM basic.model_group WHERE model_type_id = " + QString::number(modelID) + " ORDER BY id ASC"; try { QSqlQuery query = executeSQL(connectionName, strSQL); while(query.next()) { groups.append(query.value(0).toInt()); } } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取模型所含属性组名称失败,id:%1").arg(QString::number(modelID))); return groups; } return groups; } 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 " "(:type, :name, :remark)"; QVariantHash params; params.insert(":type", model.type); params.insert(":name", model.name); params.insert(":remark", model.remark); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); modelID = query.lastInsertId().toInt(); //lasatInsertId()会返回最近插入行的自增id model.id = modelID; } catch (const DatabaseException& e) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚失败时记录警告 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } //然后向model_group中插入记录,采用批量接口 /*QStringList sqlStatements; QList paramsList; for(int groupID : model.groups) { 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); paramsList << params; } try { executeBatchSQL(connectionName, sqlStatements, paramsList); } catch (const DatabaseException& e) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚失败时记录警告 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; }*/ QSqlQuery query(db); strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES (?, ?)"; if(!query.prepare(strSQL)) { LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText())); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } QVariantList modelIds, groupIds; for(int groupID : model.groups) { modelIds << modelID; groupIds << groupID; } query.addBindValue(modelIds); query.addBindValue(groupIds); if( !query.execBatch() ) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚失败时记录警告 { 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; } bool SqlQueryExecutor::modelNameExistsInDB(const QString& connectionName, const QString& name) { bool exists = false; QString strSQL = "SELECT id FROM basic.model_type WHERE model_name = \'" + name + "\'"; try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) exists = true; } catch (const DatabaseException& e) { exists = true; } return exists; } bool SqlQueryExecutor::modelTypeExistsInDB(const QString& connectionName, const QString& type) { bool exists = false; QString strSQL = "SELECT id FROM basic.model_type WHERE model_type = \'" + type + "\'"; try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) exists = true; } catch (const DatabaseException& e) { exists = true; } return exists; } bool SqlQueryExecutor::removeModel(const QString& connectionName, int modelID) { //数据库中有级联删除,只需要从model_type中删除即可 QString strSQL = "DELETE FROM basic.model_type WHERE id = :id"/* + QString::number(modelID)*/; QVariantHash params; params.insert(":id", modelID); try { executeSQL(connectionName, strSQL, params, true); } catch (const DatabaseException& e) { return false; } return true; } bool SqlQueryExecutor::addModleGrpus(const QString& connectionName, int modelID, QVector groups) { //属于批量操作,需要开启事务 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; } QSqlQuery query(db); QString strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES (?, ?)"; if(!query.prepare(strSQL)) { LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText())); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } QVariantList modelIds, groupIds; for(int groupID : groups) { modelIds << modelID; groupIds << groupID; } query.addBindValue(modelIds); query.addBindValue(groupIds); if( !query.execBatch() ) { LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText())); LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚 { 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; } const QVector SqlQueryExecutor::getAttributeGroup(const QString& connectionName) { QVector groupList; QString strSQL = "SELECT id, group_type, group_name, remark, is_public FROM basic.attribute_group ORDER BY id ASC"; try { QSqlQuery query = executeSQL(connectionName, strSQL); while(query.next()) { int id = query.value(0).toInt(); QString type = query.value(1).toString(); QString name = query.value(2).toString(); QString remark = query.value(3).toString(); bool isPublic = query.value(4).toBool(); groupList.emplace_back(id,name,type,remark,isPublic); //直接调用构造函数,避免拷贝 } } catch (const DatabaseException& e) { emit errorOccurred(QString::fromWCharArray(L"获取属性组别信息失败,详情可见日志文件")); } return groupList; } const QString SqlQueryExecutor::getAttributeGroupName(const QString& connectionName, int groupID) { QString name = ""; QString strSQL = "SELECT group_name FROM basic.attribute_group WHERE id = :id"; QVariantHash params; params.insert(":id", groupID); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); if(query.next()) name = query.value(0).toString(); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组名称失败,id:%1").arg(QString::number(groupID))); } return name; } const AttributeGroup SqlQueryExecutor::getAttributeGroupData(const QString& connectionName, int groupID) { AttributeGroup group; QString strSQL = "SELECT group_type, group_name, remark, is_public FROM basic.attribute_group WHERE id = :id"; QVariantHash params; params.insert(":id", groupID); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); if(query.next()) { QString type = query.value(0).toString(); QString name = query.value(1).toString(); QString remark = query.value(2).toString(); bool isPublic = query.value(3).toBool(); return AttributeGroup(groupID,name,type,remark,isPublic); } } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组信息失败,id:%1").arg(QString::number(groupID))); } return group; } bool SqlQueryExecutor::isPublicAttributeGroup(const QString& connectionName, int groupID) { bool isPublic = false; QString strSQL = "SELECT is_public FROM basic.attribute_group WHERE id = :id"; QVariantHash params; params.insert(":id", groupID); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); if(query.next()) isPublic = query.value(0).toBool(); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组类型失败,id:%1").arg(QString::number(groupID))); } return isPublic; } bool SqlQueryExecutor::removeAttributeGroup(const QString& connectionName, int modelID, int groupID) { //从model_attribute和model_group两个map表中对相关记录进行删除(暂时不做属性本体的删除) QStringList sqlStatements; QList paramsList; sqlStatements << "DELETE FROM basic.model_attribute WHERE model_type_id = :modelID AND attribute_group_id = :groupID"; QVariantHash params; params.insert(":modelID", modelID); params.insert(":groupID", groupID); paramsList << params; sqlStatements << "DELETE FROM basic.model_group WHERE model_type_id = :modelID AND attribute_group_id = :groupID"; params.clear(); params.insert(":modelID", modelID); params.insert(":groupID", groupID); paramsList << params; try { executeBatchSQL(connectionName, sqlStatements, paramsList, true); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"删除属性组失败,model_type_id:%1,attribute_group_id:%2").arg(modelID, groupID)); return false; } return true; } int SqlQueryExecutor::getAttributeCount(const QString& connectionName, int modelID, int groupID) { int count = 0; QString strSQL = ""; bool isPublicGroup = isPublicAttributeGroup(connectionName, groupID); if(isPublicGroup) strSQL = QString("SELECT COUNT(*) FROM basic.model_attribute_public WHERE attribute_group_id = %1").arg(groupID); else strSQL = QString("SELECT COUNT(*) FROM basic.model_attribute WHERE model_type_id = %1 AND attribute_group_id = %2").arg(modelID).arg(groupID); try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) count = query.value(0).toInt(); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败")); } return count; } int SqlQueryExecutor::getAllAttributeCount(const QString& connectionName) { int count = 0; QString strSQL = QString("SELECT COUNT(*) FROM basic.attribute"); try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) count = query.value(0).toInt(); } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败")); } return count; } bool SqlQueryExecutor::getAttributeInfo(const QString& connectionName, const QString& columns, Attribute& attribute) { QString strSQL = QString("SELECT %1 FROM basic.attribute WHERE id = %2").arg(columns).arg(attribute.id); try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) { attribute.type = query.value(0).toString(); attribute.name = query.value(1).toString(); attribute.dataTypeID = query.value(2).toInt(); attribute.dataLength = query.value(3).toInt(); attribute.defaultValue = query.value(4).toString(); attribute.isVisible = query.value(5).toInt(); } else return false; } catch (const DatabaseException& e) { LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败")); return false; } return true; } int SqlQueryExecutor::getAttributeID(const QString& connectionName, const QString& type) { int id = -1; QString strSQL = "SELECT id FROM basic.attribute WHERE attribute = \'" + type + "\'"; try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) id = query.value(0).toInt(); } catch (const DatabaseException& e) { id = -1; } return id; } bool SqlQueryExecutor::attributeTypeUseByModelGroup(const QString& connectionName, int attributeID, int modelID, int groupID) { QString strSQL; QVariantHash params; bool isPublicGroup = isPublicAttributeGroup(connectionName, groupID); if(isPublicGroup) { strSQL = "SELECT id FROM basic.model_attribute_public WHERE attribute_group_id = :groupID AND attribute_id = :attributeID"; params.insert(":groupID", groupID); params.insert(":attributeID", attributeID); } else { strSQL = "SELECT id FROM basic.model_attribute WHERE model_type_id = :modelID AND attribute_group_id = :groupID AND attribute_id = :attributeID"; params.insert(":modelID", modelID); params.insert(":groupID", groupID); params.insert(":attributeID", attributeID); } try { QSqlQuery query = executeSQL(connectionName, strSQL, params); if(query.next()) return true; } catch (const DatabaseException& e) { return false; } return false; } bool SqlQueryExecutor::batchInsertAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList attributes) { //属于批量操作,需要开启事务 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; } //先插入进属性表attribute,因为要获取插入后的自增id,所以采用逐条插入的方法 QList attributeIDList; for(const Attribute& attribute : attributes) { if(attribute.id != -1) //新建条目是通过选择已有的记录完成,此类不再做重复插入 { attributeIDList.append(attribute.id); continue; } qint64 attributeID = QDateTime::currentDateTime().toMSecsSinceEpoch(); //先向model_type中插入一条记录 QString strSQL = "INSERT INTO basic.attribute (attribute, attribute_name, data_type_id, length_precision, default_value, is_visible) VALUES " "(:type, :name, :dataType, :dataLength, :defaultValue, :isVisible)"; QVariantHash params; params.insert(":type", attribute.type); params.insert(":name", attribute.name); params.insert(":dataType", attribute.dataTypeID); params.insert(":dataLength", attribute.dataLength); params.insert(":defaultValue", attribute.defaultValue); params.insert(":isVisible", attribute.isVisible); try { QSqlQuery query = executeSQL(connectionName, strSQL, params); attributeID = query.lastInsertId().toInt(); //lasatInsertId()会返回最近插入行的自增id } catch (const DatabaseException& e) { LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } attributeIDList.append(attributeID); } //插入数据到关联表 QSqlQuery linkQuery(db); QString strSQL = ""; bool isPublicGroup = isPublicAttributeGroup(connectionName, attributeGroupID); if(isPublicGroup) strSQL = "INSERT INTO basic.model_attribute_public (attribute_group_id, attribute_id) VALUES (?, ?)"; else strSQL = "INSERT INTO basic.model_attribute (model_type_id, attribute_group_id, attribute_id) VALUES (?, ?, ?)"; if(!linkQuery.prepare(strSQL)) { LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, linkQuery.lastError().databaseText())); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } QVariantList modelIds, groupIds, attributeIds; for(const qint64& attributeID : attributeIDList) { if(!isPublicGroup) modelIds << modelID; groupIds << attributeGroupID; attributeIds << attributeID; } if(!isPublicGroup) linkQuery.addBindValue(modelIds); linkQuery.addBindValue(groupIds); linkQuery.addBindValue(attributeIds); if( !linkQuery.execBatch() ) { LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, linkQuery.lastError().databaseText())); LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚 { 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; } bool SqlQueryExecutor::batchDeleteAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList attributes) { //属于批量操作,需要开启事务 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; } QSqlQuery query(db); QString strSQL = ""; bool isPublicGroup = isPublicAttributeGroup(connectionName, attributeGroupID); if(isPublicGroup) strSQL = "DELETE FROM basic.model_attribute_public WHERE attribute_group_id = ? AND attribute_id = ?"; else strSQL = "DELETE FROM basic.model_attribute WHERE model_type_id = ? AND attribute_group_id = ? AND attribute_id = ?"; if(!query.prepare(strSQL)) { LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText())); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } QVariantList modelIds, groupIds, attributeIds; for(const int& attributeID : attributes) { if(!isPublicGroup) modelIds << modelID; groupIds << attributeGroupID; attributeIds << attributeID; } if(!isPublicGroup) query.addBindValue(modelIds); query.addBindValue(groupIds); query.addBindValue(attributeIds); if( !query.execBatch() ) { LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText())); LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚 { 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; } bool SqlQueryExecutor::batchUpdateAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList attributes) { //属于批量操作,需要开启事务 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; } QSqlQuery query(db); QString strSQL = "UPDATE basic.attribute SET attribute = ?, attribute_name = ?, data_type_id = ?, length_precision = ?, default_value = ?, is_visible = ? WHERE id = ?"; if(!query.prepare(strSQL)) { LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText())); if(!db.rollback()) // 回滚 { LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText())); } return false; } QVariantList types, names, dataTypes, lengths, defaults, isVisibles, ids; for(const Attribute& attribute : attributes) { types << attribute.type; names << attribute.name; dataTypes << attribute.dataTypeID; lengths << attribute.dataLength; defaults << attribute.defaultValue; isVisibles << attribute.isVisible; ids << attribute.id; } query.addBindValue(types); query.addBindValue(names); query.addBindValue(dataTypes); query.addBindValue(lengths); query.addBindValue(defaults); query.addBindValue(isVisibles); query.addBindValue(ids); if( !query.execBatch() ) { LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText())); LOG_INFO("DB", QString("DB Rollback")); if(!db.rollback()) // 回滚 { 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; }