MySQL Connector/C++对象销毁后重新构造失败问题求助
问题:MySQL Connector/C++ 8.0重复创建Database对象失败
现象描述
首次构造Database对象可正常连接并读写数据库,但对象销毁后再次构造新对象时,会抛出以下两种错误之一:
CDK Error: OpenSSL: error:00000000:lib(0):func(0):reason(0)CDK Error: Bad file descriptor (generic:9)
MySQL服务日志(/var/log/mysql/)无相关报错,手动调用close()方法也无法解决问题。
现有代码
Database类实现
class Database { private: std::unique_ptr<mysqlx::Session> _session; std::unique_ptr<mysqlx::Table> _table; std::unique_ptr<mysqlx::Schema> _schema; public: Database( std::string host, int port, std::string user, std::string pass, std::string schema, std::string table ) { _session = std::make_unique<mysqlx::Session> ( mysqlx::SessionOption::HOST, host, mysqlx::SessionOption::PORT, port, mysqlx::SessionOption::USER, user, mysqlx::SessionOption::PWD, pass ); _schema = std::make_unique<mysqlx::Schema>( *_session, schema ); _table = std::make_unique<mysqlx::Table>( _schema->getTable( table ) ); void write( std::map<std::string, std::string> data ); // 实现细节略 // close might be overkill? shouldn't things get cleaned up when // the object goes out of scope and is deconstructed? // inline void close() { _session->close(); _session.reset(); _table.reset(); _schema.reset(); } } };
对象实例化代码
void SomeClass::dothread_db( host,port,... etc.. ) { try { Database database(host,port,user,pass,schema,table); while (condition ) { database.write(...); // 条件变更逻辑 } database.close(); // is this even needed? } catch etc.. return; }
问题原因及修复方案
核心问题
- 语法错误:
close()方法定义在构造函数内部,属于非法语法,会导致编译错误且无法正确执行资源释放逻辑。 - 资源释放顺序错误:先关闭
_session再释放依赖它的_table和_schema,会导致悬空引用。 - 全局资源未正确初始化/清理:MySQL Connector/C++ 8.0需要全局上下文初始化,否则重复创建会话时会出现底层SSL或文件描述符泄漏。
修复步骤
1. 修正Database类结构
调整close()方法位置,修正资源释放顺序,并添加析构函数自动处理资源:
class Database { private: std::unique_ptr<mysqlx::Session> _session; std::unique_ptr<mysqlx::Table> _table; std::unique_ptr<mysqlx::Schema> _schema; public: Database( std::string host, int port, std::string user, std::string pass, std::string schema, std::string table ) { _session = std::make_unique<mysqlx::Session> ( mysqlx::SessionOption::HOST, host, mysqlx::SessionOption::PORT, port, mysqlx::SessionOption::USER, user, mysqlx::SessionOption::PWD, pass ); _schema = std::make_unique<mysqlx::Schema>( *_session, schema ); _table = std::make_unique<mysqlx::Table>( _schema->getTable( table ) ); } void write( std::map<std::string, std::string> data ); // 实现细节略 void close() { // 先释放依赖session的对象,避免悬空引用 _table.reset(); _schema.reset(); // 再关闭并释放session if (_session) { _session->close(); _session.reset(); } } // 析构函数自动调用close,确保资源必然释放 ~Database() { close(); } };
2. 添加全局资源管理
在程序启动时初始化Connector/C++全局上下文,退出时清理:
#include <mysqlx/xdevapi.h> int main() { // 初始化全局网络、SSL等资源 mysqlx::Client::init(); // ... 你的业务逻辑代码 ... // 清理全局资源,必须在所有会话销毁后调用 mysqlx::Client::shutdown(); return 0; }
3. 简化线程内对象使用
无需手动调用close(),析构函数会自动处理:
void SomeClass::dothread_db( host,port,... etc.. ) { try { Database database(host,port,user,pass,schema,table); while (condition ) { database.write(...); // 条件变更逻辑 } // 无需手动调用close(),对象销毁时析构函数自动执行资源释放 } catch (const mysqlx::Error& e) { std::cerr << "MySQL错误: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "错误: " << e.what() << std::endl; } return; }
额外说明
mysqlx::Client::init()和mysqlx::Client::shutdown()是Connector/C++ 8.0的全局资源管理接口,负责初始化底层网络、SSL等组件,必须在所有会话创建前调用init,所有会话销毁后调用shutdown。- 析构函数自动调用
close(),确保无论对象正常退出还是异常退出,资源都能被正确释放,避免泄漏。
内容的提问来源于stack exchange,提问作者astronomerdave
相关产品推荐
相关产品推荐

