c++怎么操作mysql数据库_c++ mysql-connector连接与增删改查【方法】

必须安装官方mysql-connector-c++ 8.0.33+版本,它支持X DevAPI(mysqlx::Session等),链接用-lmysqlcppconn而非-lmysqlclient,连接应优先选用mysqlx::Session而非sql::Connection。

用 mysql-connector-c++ 连接数据库前,先确认是否装对了库

很多人卡在第一步:编译通不过,报 mysqlx::Session 找不到、mysqlx::Schema 未声明,或链接时提示 undefined reference to mysqlx::get_session。这不是代码写错了,大概率是装了 libmysqlclient(C API)却误当成了 C++ connector,或者装了旧版(8.0.22 之前)但用了新版 API。

必须用官方 mysql-connector-c++(不是 mysql-client),且推荐 8.0.33+ 版本,它默认启用 X DevAPI(支持 mysqlx:: 命名空间),也兼容传统 SQL 模式。安装后检查关键头文件是否存在:

#include   // 新版 X DevAPI
// 或
#include 
#include   // 旧版 JDBC 风格 API(已逐步弃用)

链接时加 -lmysqlcppconn(注意不是 -lmysqlclient),CMake 中要 find_package(mysqlcppconn REQUIRED)。

连接 MySQL 用 mysqlx::Session 还是 sql::Connection?

mysqlx::Session。它基于 X Protocol,支持 JSON 文档、集合操作、事务自动管理,API 更现代;而 sql::Connection 是仿 JDBC 的老接口,不支持 MySQL 8.0+ 的新特性(如角色、缓存 SHA2 登录),且文档维护停滞。

连接字符串格式也不同:

  • mysqlx::Session:用 mysqlx://user:password@host:port/database
  • sql::Connection:用 tcp://host:port + 单独 setSchema(),且密码需通过 sql::SQLString

示例连接代码(带异常捕获):

try {
    mysqlx::Session session("mysqlx://root:pass@127.0.0.1:33060/testdb");
    std::cout << "Connected successfully\n";
} catch (const mysqlx::Error& e) {
    std::cerr << "Connection failed: " << e.what() << " (" << e.getErrorCode() << ")\n";
}

执行 INSERT/UPDAT

E/DELETE 必须用 execute(),不能用 sql::Statement::executeUpdate()

mysqlx::Session 下,没有 executeUpdate() 这种方法。所有 DML 都走 session.sql("...").execute(),返回 mysqlx::SqlResult;查询才用 session.sql("SELECT ...").execute() 得到 mysqlx::RowResult

常见错误写法:session.sql("INSERT ...").executeUpdate() → 编译失败,因为 mysqlx::SqlStatement 没这方法。

正确写法要点:

  • INSERT 返回影响行数:auto res = session.sql("INSERT INTO t1 VALUES (?, ?)").bind(123, "abc").execute(); res.getAffectedItemsCount();
  • UPDATE/DELETE 同理,用 bind() 防止 SQL 注入,参数位置从 1 开始(不是 0)
  • 事务控制:用 session.startTransaction() + session.commit() / session.rollback()

SELECT 查询结果取值时,别直接用 [] 索引访问 Row

mysqlx::Row 不支持 row[0] 这种语法。必须用 row[0].get()row[1].get<:string>() 显式指定类型,否则运行时报 std::bad_cast 或静默截断。

字段名访问更安全(尤其涉及 NULL):

auto result = session.sql("SELECT id, name FROM users WHERE id = ?").bind(42).execute();
if (auto row = result.fetchOne()) {
    int id = row["id"].get();           // 推荐:按列名
    std::string name = row["name"].get();
    // 若 name 可能为 NULL,改用:row["name"].isNull() ? "" : row["name"].get()
}

注意:字段名大小写敏感,且必须和 SELECT 中写的完全一致(包括别名)。

最易被忽略的是连接池和生命周期管理:mysqlx::Session 对象不是线程安全的,不要跨线程复用;频繁创建销毁开销大,建议封装成连接池,或至少用 RAII 管理(例如放在局部作用域内,靠析构自动关闭)。另外,X Protocol 默认端口是 33060,不是传统 3306,连不上时先检查端口配置。