You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++使用libmysqlclient.a连接MySQL偶现初始化失败问题咨询

问题解答

1. 代码存在的问题及资源泄漏情况

你的代码存在多处明显缺陷,也是导致偶发初始化失败的核心原因:

  • 指针未初始化:构造函数没有对sock、my_sql两个私有指针做初始化,野指针可能导致后续资源判断、释放逻辑出现不可预期的异常。
  • 资源泄漏严重:
    1. executeSql方法中获取的MYSQL_RES结果集用完后没有调用mysql_free_result释放,每次查询都会泄漏内存,累计到一定程度会导致mysql_init申请内存失败,就是你遇到的偶发Init failed问题。
    2. connInit中如果mysql_real_connect连接失败,已经通过mysql_init创建的my_sql对象没有释放,直接返回会造成内存泄漏。
    3. 析构函数为空,如果业务代码忘记手动调用close方法,连接资源和MYSQL对象会直接泄漏。
  • 逻辑判断错误:
    1. mysql_real_connect失败时返回的是NULL,你用sock < 0判断指针有效性属于逻辑错误,不同平台下指针比较规则不同,可能导致正常连接被误判为失败,也可能漏判连接失败的情况。
    2. connInit方法执行成功后没有写return 0,属于未定义行为,函数返回值可能是随机值,导致业务逻辑误判初始化失败。
    3. executeSql方法没有判断mysql_query的返回值,SQL执行失败时后续取结果的逻辑会直接报错。
  • 类设计缺陷:没有禁用拷贝构造、拷贝赋值函数,一旦意外复制了ConnMysql对象,会导致两个对象持有同一份MySQL连接资源,最终出现双重释放的问题。

2. 获取MySQL初始化/连接失败具体原因的方法

你可以直接调用MySQL客户端库提供的错误查询函数获取详情:

  • 如果mysql_init返回NULL,调用mysql_error(NULL)就能获取初始化失败的错误信息,调用mysql_errno(NULL)可以拿到对应的错误码。
  • 如果mysql_real_connect返回NULL,传入mysql_init返回的MYSQL对象作为参数,调用mysql_error(my_sql)、mysql_errno(my_sql)就能拿到连接失败的具体原因,比如账号密码错误、连接数超限、网络超时、服务端不可用等。

修改后的核心逻辑参考:

// 构造函数初始化指针
ConnMysql::ConnMysql():sock(nullptr), my_sql(nullptr){
}

// 析构函数自动释放资源,避免漏调用close泄漏
ConnMysql::~ConnMysql(){
    close();
}

int ConnMysql::connInit(const char* host,int port,const char* user,const char* password,const char* database){
    // 先释放之前的资源,避免重复调用connInit导致泄漏
    close();
    my_sql = mysql_init(NULL);
    if (my_sql == NULL) {
        fprintf(stderr, "Init failed, err: %s, errno: %d\n", mysql_error(NULL), mysql_errno(NULL));
        return -1;
    }

    sock = mysql_real_connect(my_sql, host,
                user, password, database, port, NULL, CLIENT_MULTI_STATEMENTS);
    
    if (sock == NULL) {
        fprintf(stderr, "Connect failed, err: %s, errno: %d\n", mysql_error(my_sql), mysql_errno(my_sql));
        // 连接失败要释放已经创建的my_sql对象
        mysql_close(my_sql);
        my_sql = nullptr;
        return -1;
    }
    // 补充成功返回值
    return 0;
}

int ConnMysql::executeSql(const char* sql, std::vector<std::string> &v) {
    if (sock == nullptr) {
        return -1;
    }
    int ret = mysql_query(sock, sql);
    if (ret != 0) {
        fprintf(stderr, "Execute sql failed, err: %s\n", mysql_error(sock));
        return -1;
    }
    MYSQL_RES *res_ptr = mysql_store_result(sock);
    if(res_ptr == nullptr) {   
        printf("Get data from mysql failed, err: %s\n", mysql_error(sock));            
        return -1;
    }  
    MYSQL_ROW sqlrow;
    while((sqlrow = mysql_fetch_row(res_ptr))) {
        if (sqlrow[0] != nullptr) {
            v.push_back(std::string(sqlrow[0]));
        }
    }
    // 补充结果集释放,避免内存泄漏
    mysql_free_result(res_ptr);
    return 0;
}

void ConnMysql::close() {
    if (sock != nullptr) {
        mysql_close(sock);
        sock = nullptr;
    }
    my_sql = nullptr;
}

内容的提问来源于stack exchange,提问作者Yongqi Z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:24:03