C++怎么连接MySQL数据库 C++操作MySQL增删改查完整版【数据库】

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

用 mysqlcppconn 连接 MySQL 需要哪些依赖和头文件

必须链接 mysqlcppconn(即 MySQL Connector/C++ 8.0+ 的库),不是旧版 libmysqlclient。头文件只需包含 #include #include ,其他如 sql::Statementsql::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_NAMESSL_MODE,否则中文乱码或远程连接被拒很常见。

认证失败时,driver->connect() 不抛异常而是返回空指针(C++ 8.0.29+ 默认行为),直接解引用会 crash。必须检查返回值。

  • 推荐连接方式:
    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 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(),否则乱码
连接池、事务控制、异步执行这些属于进阶场景,底层仍基于上述四点。最常出问题的是驱动版本错配、NULL 值误判、以及忘记检查 connrs->next() 返回值 —— 这些地方不加防护,程序跑一两天就 core dump。