如何在C++中多次调用mysql_fetch_row不返回NULL(MySQL C API)
问题根源
mysql_store_result返回的结果集是单向遍历的,首次通过mysql_fetch_row遍历完全部行后,结果集游标会停在末尾,后续再调用mysql_fetch_row会直接返回NULL,这是MySQL C API的正常机制。- 你之前在循环内直接调用
mysql_store_result触发崩溃的原因有两个:- 没有释放上一次申请的
MYSQL_RES资源,存在内存泄漏同时会导致连接状态异常 - 没有重新执行
mysql_query查询语句,连接上没有未读取的新结果集,mysql_store_result直接返回NULL,后续操作空指针就触发了访问冲突报错
- 没有释放上一次申请的
- 你原有代码还存在
MYSQL_RES资源未释放的问题,会持续占用内存。
修复方案
这里提供两种可选实现:
方案1:每次校验输入前重新查询数据库(适合角色列表会实时更新的场景)
把查询、结果集获取、结果集释放的逻辑全部放到输入校验循环内部,每次用户输入无效编号时重新拉取最新的角色列表:
void listarPersonagem(MYSQL* conn) { int escolha = -1; std::map<int, int> indexMap; const char* q = "SELECT * FROM personagem"; while(escolha < 0 || escolha > indexMap.size()) { system("cls"); std::cout << "\t\t\t\t Personagens\n" << std::endl; indexMap.clear(); // 每次循环重新执行查询 if(mysql_query(conn, q) != 0) { // 可自行添加查询失败的报错逻辑 break; } MYSQL_RES* res = mysql_store_result(conn); if(res == nullptr) { break; } int i = 1; MYSQL_ROW row; while((row = mysql_fetch_row(res)) != nullptr) { std::cout << i << " - " << row[1] << std::endl; indexMap.insert({i, std::atoi(row[0])}); i++; } // 用完立即释放结果集资源 mysql_free_result(res); std::cout << "0 - Voltar" << std::endl; std::cout << "\n\n=>"; std::cin >> escolha; } int id = escolha != 0 ? indexMap[escolha] : 0; }
方案2:首次查询缓存所有角色数据(性能更高,适合角色列表不会频繁变动的场景)
只查一次数据库,把所有角色信息存到本地容器,后续输入校验直接用本地缓存,不需要反复访问数据库:
void listarPersonagem(MYSQL* conn) { std::map<int, std::string> charaList; std::map<int, int> indexMap; int escolha = -1; // 仅执行一次查询,把数据缓存到本地 if(mysql_query(conn, "SELECT * FROM personagem") == 0) { MYSQL_RES* res = mysql_store_result(conn); if(res != nullptr) { MYSQL_ROW row; int i = 1; while((row = mysql_fetch_row(res)) != nullptr) { charaList.insert({i, row[1]}); indexMap.insert({i, std::atoi(row[0])}); i++; } mysql_free_result(res); } } while(escolha < 0 || escolha > charaList.size()) { system("cls"); std::cout << "\t\t\t\t Personagens\n" << std::endl; for(auto& item : charaList) { std::cout << item.first << " - " << item.second << std::endl; } std::cout << "0 - Voltar" << std::endl; std::cout << "\n\n=>"; std::cin >> escolha; } int id = escolha != 0 ? indexMap[escolha] : 0; }
内容的提问来源于stack exchange,提问作者Yasushiki
相关产品推荐
相关产品推荐

