需链接 libmysqlcppconn(非 libmysqlclient),头文件仅需 #include <sql/mysql_connection.h> 和 <sql/mysql_pstmt.h>;Ubuntu 安装 libmysqlcppconn-dev,编译加 -lmysqlcppconn,运行时确保 libmysqlcppconn.so.x 在 LD_LIBRARY_PATH 中。

用 mysqlcppconn 连接 MySQL 需要哪些依赖和头文件
必须链接 mysqlcppconn(即 MySQL Connector/C++ 8.0+ 的库),不是旧版 libmysqlclient。头文件只需包含 #include <sql/mysql_connection.h> 和 #include <sql/mysql_pstmt.h>,其他如 sql::Statement、sql::ResultSet 等类型都从这里导出。
常见错误是混用 Connector/C++ 1.1(已废弃)和 8.0+:前者用 mysql_driver.h,后者用 mysql_connection.h;链接时若写错库名(比如写成 -lmysqlclient),会报 undefined reference to 'sql::mysql::MySQL_Driver::get_mysql_driver_instance()'。
- Ubuntu/Debian 安装命令:
sudo apt install libmysqlcppconn-dev - 编译时加链接参数:
-lmysqlcppconn,不是-lmysqlclient - 运行时确保
libmysqlcppconn.so.7(或对应版本)在LD_LIBRARY_PATH中
如何正确初始化连接并处理认证失败
连接不能只靠 sql::mysql::MySQL_Driver::get_mysql_driver_instance() 就完事。必须显式设置连接属性,尤其是 OPT_SET_CHARSET_NAME 和 SSL_MODE,否则中文乱码或远程连接被拒很常见。
认证失败时,driver->connect() 不抛异常而是返回空指针(C++ 8.0.29+ 默认行为),直接解引用会 crash。必须检查返回值。
立即学习“C++免费学习笔记(深入)”;
- 推荐连接方式:
sql::SQLString url("tcp://127.0.0.1:3306"); sql::Properties props; props["user"] = "root"; props["password"] = "123456"; props["OPT_SET_CHARSET_NAME"] = "utf8mb4"; props["SSL_MODE"] = "disabled"; // 本地开发可关,生产环境建议 enabled std::unique_ptr<sql::Connection> conn(driver->connect(url, props)); if (!conn) { throw std::runtime_error("Connection failed"); } - 密码含特殊字符(如
@、/)需 URL 编码,否则解析失败 - MySQL 8.0 默认 auth plugin 是
caching_sha2_password,Connector/C++ 8.0.23+ 才原生支持;旧版需在 MySQL 中执行:ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';
为什么用 PreparedStatement 而不是 Statement 做增删改查
sql::Statement 拼 SQL 字符串极易引发 SQL 注入,且无法复用执行计划。而 sql::PreparedStatement 支持占位符 ?,自动转义参数,性能也更好。
注意:MySQL Connector/C++ 中 executeUpdate() 对 INSERT/UPDATE/DELETE 返回影响行数(int64_t),但 executeQuery() 才返回 sql::ResultSet;误用会导致编译失败或运行时异常。
- 插入示例:
auto pstmt = conn->prepareStatement("INSERT INTO users(name, age) VALUES (?, ?)"); pstmt->setString(1, "张三"); pstmt->setInt(2, 25); int64_t rows = pstmt->executeUpdate(); // 返回 1 - 查询后必须调用
rs->next()才能读数据,否则rs->getString(1)会抛sql::InvalidArgumentException - 不要在循环里反复
prepareStatement,应复用pstmt对象
ResultSet 读取字段时容易踩的坑
字段索引从 1 开始(不是 0),且 getString() 等方法对 NULL 值返回空字符串而非 nullptr —— 无法靠判空判断是否为 NULL。必须先调 wasNull()。
另外,ResultSet 生命周期绑定到 PreparedStatement,一旦 pstmt 被销毁或执行新查询,旧 rs 自动失效。不能缓存 rs 指针跨作用域使用。
- 安全读取方式:
if (rs->next()) { std::string name = rs->getString(1); if (rs->wasNull()) { // 字段实际是 NULL } } - 字段名大小写敏感,MySQL 表名默认小写,但列名在结果集中按定义大小写返回;建议统一用索引访问
- 大文本字段(如
TEXT)用getString()没问题,但二进制字段(BLOB)必须用getBytes(),否则乱码
conn 和 rs->next() 返回值 —— 这些地方不加防护,程序跑一两天就 core dump。










