做过了众多的项目,只要是用了数据库的项目,基本上还有一个需求就是,提供一个界面用来初始化数据库,相当于恢复出厂设置的数据,一般恢复出厂设置需要复位的是配置文件、数据库文件、布局文件这几种,其中配置文件和布局文件都可以通过先删除原来的文件,然后重新生成新的默认文件来实现,而数据库文件只有sqlite才是文件型的数据库,也可以采用类似方式,比如将出厂设置的数据库文件放在资源文件,需要恢复的时候,先删除原来的文件,然后从资源文件拷贝出来对应的文件即可,同时还要赋值可读写权限。
数据库恢复出厂,还有一种更好的办法就是通过执行sql语句去实现,这种办法通用各种数据库,比如sqlite、mysql、posggres等,都可以通过执行sql语句的方式,新建数据库以及重置数据库表,基本上的流程都是:删除数据库(有些不能通过删除数据库形式的则删除数据库表)、新建数据库、新建数据库表、添加初始数据。经过这几个步骤以后,就会生成一个全新的干干净净的按照自己要求的数据库。有些时候,我们不想去挨个界面中删除清空数据,直接来个恢复出厂,清清爽爽干干净净的一步到位。
既然是通用的数据库设置,那当然需要支持多种数据库了,整个轮子组件还是花了点心思的,完善了很多年,在各种项目中验证和迭代,形成现在的规范。数据库的相关参数就几个:数据库类型、数据库地址、数据库端口、数据库名称、数据库用户名称、数据库用户密码、其中数据库地址既可以填网址也可以填IP地址。这些参数可以直接在界面上选择,选择好以后存储到配置文件,同时还提供检测连接功能,测试下填入的信息是否正确,默认还可以自动填入数据库的端口,比如mysql是3306,sqlserver是1433。
void frmConfigDb::on_btnConnect_clicked() { { DbInfo dbInfo; dbInfo.connName = connName; dbInfo.dbName = AppConfig::LocalDbName; dbInfo.hostName = AppConfig::LocalHostName; dbInfo.hostPort = AppConfig::LocalHostPort; dbInfo.userName = AppConfig::LocalUserName; dbInfo.userPwd = AppConfig::LocalUserPwd; QString dbType = AppConfig::LocalDbType.toUpper(); if (dbType == "SQLITE") { dbInfo.dbName = DbHelper::getDbDefaultFile(connFlag); if (QFile(dbInfo.dbName).size() <= 4) { QUIHelper::showMessageBoxError("数据库文件不存在!", 5); return; } } QSqlDatabase database; if (DbHelper::initDatabase(true, dbType, database, dbInfo)) { if (database.open()) { database.close(); QUIHelper::showMessageBoxInfo("打开数据库成功!", 3); } else { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3); } } else { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3); } } QSqlDatabase::removeDatabase(connName); } void frmConfigDb::on_btnInit_clicked() { QString sqlName = QString("%1/db/%2.sql").arg(QUIHelper::appPath()).arg(connFlag); QFile file(sqlName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QUIHelper::showMessageBoxError("数据库脚本文件打开失败!", 3); return; } QElapsedTimer time; time.start(); { DbInfo dbInfo; dbInfo.connName = connName; dbInfo.dbName = AppConfig::LocalDbName; dbInfo.hostName = AppConfig::LocalHostName; dbInfo.hostPort = AppConfig::LocalHostPort; dbInfo.userName = AppConfig::LocalUserName; dbInfo.userPwd = AppConfig::LocalUserPwd; QString dbType = AppConfig::LocalDbType.toUpper(); if (dbType == "SQLITE") { dbInfo.dbName = DbHelper::getDbDefaultFile(connFlag); //如果文件存在则先删除原来的数据库文件,貌似win上不行 QFile file(dbInfo.dbName); if (file.exists()) { bool ok = file.remove(); if (!ok) { qDebug() << TIMEMS << "remove error" << dbInfo.dbName; } //清空所有表 QStringList tables = QSqlDatabase::database().tables(); foreach (QString table, tables) { DbHelper::clearTable(table, dbType); qDebug() << TIMEMS << "clearTable" << table; } //关闭默认数据库连接 QSqlDatabase::database().close(); } } //初始化数据库连接并打开数据库 QSqlDatabase database; if (!DbHelper::initDatabase(true, dbType, database, dbInfo)) { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3); return; } if (!database.open()) { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3); return; } QSqlQuery query(QSqlDatabase::database(connName)); //第一步:删除原有数据库 QString sql = QString("DROP DATABASE %1;").arg(dbInfo.dbName); qDebug() << TIMEMS << "sql:" << sql << "result:" << query.exec(sql); //第二步:新建数据库 sql = QString("CREATE DATABASE %1;").arg(dbInfo.dbName); qDebug() << TIMEMS << "sql:" << sql << "result:" << query.exec(sql); //第三步:切换到新建的数据库库并执行建表语句 database.close(); if (!DbHelper::initDatabase(false, dbType, database, dbInfo)) { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3); return; } if (!database.open()) { QString error = database.lastError().text(); QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3); return; } //将执行出错的sql语句输出到文件方便查看 QString fileName2 = QString("%1/db/error.sql").arg(QUIHelper::appPath()); QFile file2(fileName2); QSqlQuery query2(QSqlDatabase::database(connName)); sql = "BEGIN;"; qDebug() << TIMEMS << "sql:" << sql << "result:" << query2.exec(sql); while (!file.atEnd()) { sql = QString::fromUtf8(file.readLine()); sql.replace("\n", ""); //有些数据库不支持的语句跳过去 if (DbHelper::existNoSupportSql(sql)) { continue; } //重新纠正sql语句 DbHelper::checkSql(dbType, sql); if (!query2.exec(sql)) { //打印及输出错误信息 QString error = query2.lastError().text(); qDebug() << TIMEMS << "sql:" << sql << error; //没打开则先打开 if (!file2.isOpen()) { file2.open(QFile::WriteOnly | QFile::Append); } QString msg = QString("时间[%1] 语句: %2 错误: %3\n").arg(DATETIME).arg(sql).arg(error); file2.write(msg.toUtf8()); } } sql = "COMMIT;"; qDebug() << TIMEMS << "sql:" << sql << "result:" << query2.exec(sql); database.close(); //sqlite数据库的话再执行下压缩减少体积 if (dbType == "SQLITE") { DbHelper::execSql("VACUUM;"); } } QSqlDatabase::removeDatabase(connName); double ms = time.elapsed(); QString info = QString("数据库脚本执行成功,总共用时 %1 秒!\n记得重新启动程序!").arg(QString::number(ms / 1000, 'f', 1)); QUIHelper::showMessageBoxInfo(info, 3); }