前言
C++聊天服务器项目加上数据库连接池时出了bug。可我不会在Linux环境下调试,浪费了很多时间。虽然最后将这个bug解决了,但是这给了我一个警钟:必须要会GDB的简单使用
我将复现bug,使用GDB一步步地将bug揪出来。
其实这个bug,我事后回想了下,并不离谱,稍微推理下就应该知道大概在哪里出了岔子。
1、bug 复现
mysql Commands out of sync; you can’t run this command now
数据库连接池在并发环境下,执行select后出错(用户登录)(insert随便用)(第一条select就报错)。当时的解决方向跑到了数据库的锁(被网上搜到的指偏了):读的时候对表加了独占锁。
现在给出不需要调试的找bug思路:第一条select就报错,但是在此之前数据库并没有读表!所以大概率不是锁的问题,而是登录模块出了问题。
当时的bug是这样的:处理登录功能会跳转到usermodel.cpp
里面执行这个函数(未修改版):
// 根据用户号码查询用户信息
User UserModel::query(int id)
{
// 1.组装sql语句
char sql[1024] = {0};
sprintf(sql, "select * from user where id = %d", id);
MySQL mysql;
MYSQL_RES *res = mysql.query(sql);
if (res != nullptr)
{
MYSQL_ROW row = mysql_fetch_row(res);
if (row != nullptr)
{
User user;
user.setId(atoi(row[0]));
user.setName(row[1]);
user.setPwd(row[2]);
user.setState(row[3]);
mysql_free_result(res);
return user;
}
}
return User();
}
我是在已经写好的代码上改的,向线程池申请资源时不需要再连接,所以我把所有的connect()删了,但是这个角落的删了连接、且不是向池申请,所以是空连接。
ConnectionPool* cp = ConnectionPool::getConnectionPool();
shared_ptr<MySQL>mysql = cp->getConnection();
MYSQL_RES *res = mysql->query(sql);
那么,如果我当时会gdb调试的话,情况会怎样呢?
2、GDB
设置断点 b chatservice.cpp:67
之后使用 run
运行到断点,再 n/s/finish
交替看运行过程。
比cout加ctrl点击还是要方便许多的。可以看到执行过程,将排查范围精准下来。