什么是 Connector/C++
MySQL Connector/C++ 是 MySQL 官方提供的 C++ 客户端库。
它支持两套主要 API:
X DevAPI
- 面向文档数据库和关系表操作的现代 API
- 基于 MySQL X Protocol
- 支持:
- Schema / Collection / Table
- 文档 CRUD
- SQL 执行
- 事务
- 预处理风格参数绑定
- 推荐用于 MySQL 8.x 和 X Plugin 环境
头文件常见:
1
| #include <mysqlx/xdevapi.h>
|
经典 JDBC/SQL 风格 API(Legacy API)
更接近传统 SQL 驱动使用方式
安装 Connector/C++
Linux
以通过:
- 官方 MySQL 安装包
- 系统包管理器
- 手动下载安装
有时仓库包较旧:
1 2
| sudo apt update sudo apt install libmysqlcppconn-dev
|
注意:有些发行版仓库里的版本可能不是最新的 8.x
macOS
如果 Homebrew 提供可用包,可尝试:
1
| brew install mysql-connector-c++
|
如果没有或版本不合适,通常去 MySQL 官方下载更稳。
Windows
通常从 MySQL 官方下载安装包:
然后在 Visual Studio 工程里配置:
- Include 目录
- Library 目录
- 链接库
基本开发流程
使用 Connector/C++ 的典型流程:
- 加载驱动
- 建立连接
- 创建语句对象
- 执行 SQL
- 读取结果集
- 关闭对象 / 自动释放
- 处理异常
环境要求
服务端要求
要使用 X DevAPI,你的 MySQL 服务端需要支持 X Protocol,通常意味着:
- MySQL 8.0+
- 启用了 X Plugin
- 默认端口通常是:
- 经典协议:
3306
- X Protocol:
33060
可在 MySQL 中检查:
1
| SHOW VARIABLES LIKE 'mysqlx%';
|
如果能看到 mysqlx_port 等配置,说明 X Plugin 通常已启用。
客户端要求
需要安装:
- MySQL Connector/C++ 8.x
- 头文件
- 动态库 / 静态库
常用头文件通常是:
1
| #include <mysqlx/xdevapi.h>
|
基本概念
X DevAPI 里最重要的对象层次通常是:
- Session:与 MySQL 服务器建立 X 协议连接
- Schema:对应数据库
- Collection:文档集合,类似 NoSQL collection
- Table:关系表
- Result / RowResult / DocResult:查询结果集
- SqlStatement:执行原生 SQL
命名空间:
链接数据库
最简单的链接方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <mysqlx/xdevapi.h>
int main() { try { mysqlx::Session sess("localhost", 33060, "root", "password"); std::cout << "Connected successfully!" << std::endl; } catch (const mysqlx::Error &err) { std::cerr << "Error: " << err << std::endl; } catch (std::exception &ex) { std::cerr << "STD Exception: " << ex.what() << std::endl; } }
|
使用URL链接
1
| mysqlx::Session sess("mysqlx://root:password@localhost:33060");
|
也可以指定schema:
1
| mysqlx::Session sess("mysqlx://root:password@localhost:33060/test");
|
链接选项方式
1 2 3 4 5 6
| mysqlx::SessionSettings settings( "localhost", 33060, "root", "password" );
mysqlx::Session sess(settings);
|
更完整的:
1 2 3 4 5 6 7 8
| mysqlx::SessionSettings settings( mysqlx::SessionOption::HOST, "localhost", mysqlx::SessionOption::PORT, 33060, mysqlx::SessionOption::USER, "root", mysqlx::SessionOption::PWD, "password" );
mysqlx::Session sess(settings);
|
获取schema
Schema 对应 MySQL 中的数据库。
1 2
| mysqlx::Session sess("localhost", 33060, "root", "password"); mysqlx::Schema db = sess.getSchema("test");
|
如果schema不存在:
1
| mysqlx::Schema db = sess.createSchema("test_db", true);
|
第二个参数为 true 时,一般表示“如果不存在则创建 / 容错处理”,具体行为依版本而异,生产中建议明确检查。
删除schema:
1
| sess.dropSchema("test_db");
|
使用 Collection(文档模型)
Collection 是 X DevAPI 中处理 JSON 文档的主要对象。
创建Collection
1 2
| mysqlx::Schema db = sess.getSchema("test"); mysqlx::Collection coll = db.createCollection("my_collection", true);
|
获取已存在的Collection:
1
| mysqlx::Collection coll = db.getCollection("my_collection");
|
删除Collection:
1
| db.dropCollection("my_collection");
|
插入文档
插入单个文档
1
| coll.add(R"({ "name": "Alice", "age": 25 })").execute();
|
插入多个文档
1 2 3 4
| coll.add( R"({ "name": "Bob", "age": 30 })", R"({ "name": "Carol", "age": 28 })" ).execute();
|
使用 mysqlx::Dbdoc
1 2
| mysqlx::DbDoc doc = mysqlx::DbDoc(R"({ "name": "David", "age": 40 })"); coll.add(doc).execute();
|
查询文档
查询全部
1 2 3 4 5
| mysqlx::DocResult res = coll.find().execute();
for (mysqlx::DbDoc doc : res) { std::cout << doc << std::endl; }
|
带条件查询
1 2 3 4
| mysqlx::DocResult res = coll.find("age > 26").execute(); for (mysqlx::DbDoc doc : res) { std::cout << doc << std::endl; }
|
排序和限制
1 2 3 4
| mysqlx::DocResult res = coll.find("age >= 25") .sort("age DESC") .limit(10) .execute();
|
参数绑定
1 2 3 4
| mysqlx::DocResult res = coll.find("age > :age and name = :name") .bind("age", 20) .bind("name", "Alice") .execute();
|
更新文档
1 2 3
| coll.modify("name = 'Alice'") .set("age", 26) .execute();
|
可链式调用多个修改:
1 2 3
| coll.modify("age < 18") .set("status", "minor") .execute();
|
还可使用:
set()
unset()
patch()
arrayAppend()
arrayInsert()
例如:
1 2 3
| coll.modify("name = 'Bob'") .unset("unused_field") .execute();
|
删除文档
1
| coll.remove("age < 18").execute();
|
删除全部文档(慎用):
1
| coll.remove("true").execute();
|
获取自动生成的文档 ID
如果文档没有 _id,MySQL 可能会自动生成。
1 2 3 4 5 6
| mysqlx::Result res = coll.add(R"({ "name": "Eve" })").execute();
std::vector<std::string> ids = res.getGeneratedIds(); for (const auto &id : ids) { std::cout << "Generated ID: " << id << std::endl; }
|
使用 Table(关系模型)
X DevAPI 不仅能操作文档,也能操作普通关系表。
获取表对象
1 2
| mysqlx::Schema db = sess.getSchema("test"); mysqlx::Table tab = db.getTable("users");
|
插入数据
1 2 3 4
| tab.insert("name", "age") .values("Alice", 25) .values("Bob", 30) .execute();
|
查询数据
简单查询
1 2 3 4 5 6 7 8
| mysqlx::RowResult res = tab.select("id", "name", "age").execute();
for (mysqlx::Row row : res) { std::cout << "id=" << row[0] << ", name=" << row[1] << ", age=" << row[2] << std::endl; }
|
带条件
1 2 3 4 5
| mysqlx::RowResult res = tab.select("id", "name") .where("age > 20") .orderBy("age DESC") .limit(5) .execute();
|
参数绑定
1 2 3 4
| mysqlx::RowResult res = tab.select("id", "name") .where("age > :age") .bind("age", 18) .execute();
|
更新数据
1 2 3 4
| tab.update() .set("age", 35) .where("name = 'Bob'") .execute();
|
参数绑定方式:
1 2 3 4 5
| tab.update() .set("age", 40) .where("name = :name") .bind("name", "Alice") .execute();
|
删除数据
1 2 3
| tab.remove() .where("age < 18") .execute();
|
读取单行字段
1 2 3 4 5 6 7 8
| mysqlx::RowResult res = tab.select("id", "name").where("id = 1").execute(); mysqlx::Row row = res.fetchOne();
if (!row.isNull()) { int id = row[0]; std::string name = static_cast<std::string>(row[1]); std::cout << id << ", " << name << std::endl; }
|
注意:不同版本中 Row / Value 的转换写法可能略有区别。
常见方式包括显式转换或使用 .get<T>() 风格接口(取决于具体版本 API)。
执行原生 SQL
如果某些操作 X DevAPI 不方便,可以直接执行 SQL。
执行 SQL
1 2 3
| mysqlx::SqlResult res = sess.sql("SELECT id, name FROM users WHERE age > ?") .bind(20) .execute();
|
遍历结果:
1 2 3 4
| mysqlx::Row row; while ((row = res.fetchOne())) { std::cout << row[0] << ", " << row[1] << std::endl; }
|
DDL 示例
1 2 3 4 5 6
| sess.sql( "CREATE TABLE IF NOT EXISTS users (" "id INT PRIMARY KEY AUTO_INCREMENT, " "name VARCHAR(50), " "age INT)" ).execute();
|
事务处理
X DevAPI 支持事务。
基本事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| try { sess.startTransaction();
mysqlx::Schema db = sess.getSchema("test"); mysqlx::Table tab = db.getTable("users");
tab.insert("name", "age").values("Tom", 22).execute(); tab.insert("name", "age").values("Jerry", 23).execute();
sess.commit(); } catch (const mysqlx::Error &err) { std::cerr << "Transaction error: " << err << std::endl; sess.rollback(); }
|
常见结果对象
mysqlx::Result
通常用于增删改等非查询操作:
可获取:
示例:
1 2 3 4 5
| mysqlx::Result res = tab.insert("name", "age") .values("Alice", 25) .execute();
std::cout << "Affected items: " << res.getAffectedItemsCount() << std::endl;
|
mysqlx::RowResult
用于表查询和 SQL 查询返回行数据。
1
| mysqlx::RowResult res = tab.select("id", "name").execute();
|
mysqlx::DocResult
用于集合文档查询。
1
| mysqlx::DocResult res = coll.find().execute();
|
索引操作(Collection)
Collection 可以创建索引,提高文档查询效率。
创建索引
1 2 3 4 5 6 7
| coll.createIndex("idx_age", R"( { "fields": [ { "field": "$.age", "type": "INT", "required": false } ] } )").execute();
|
唯一索引示例
1 2 3 4 5 6 7 8
| coll.createIndex("idx_email_unique", R"( { "fields": [ { "field": "$.email", "type": "TEXT(100)" } ], "unique": true } )").execute();
|
删除索引:
1
| coll.dropIndex("idx_age");
|
注意:Collection 索引定义是 JSON 格式,字段路径常写为 $.fieldName。
错误处理
X DevAPI 常见异常类型:
mysqlx::Error
- 标准异常
std::exception
推荐统一写法:
1 2 3 4 5 6 7 8 9 10 11 12
| try { mysqlx::Session sess("localhost", 33060, "root", "password"); } catch (const mysqlx::Error &err) { std::cerr << "MySQL Error: " << err.what() << std::endl; } catch (const std::exception &ex) { std::cerr << "Exception: " << ex.what() << std::endl; } catch (...) { std::cerr << "Unknown error" << std::endl; }
|
完整示例:文档操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <mysqlx/xdevapi.h>
int main() { try { mysqlx::Session sess("localhost", 33060, "root", "password");
mysqlx::Schema db = sess.getSchema("test"); mysqlx::Collection coll = db.createCollection("people", true);
coll.add(R"({ "name": "Alice", "age": 25 })").execute(); coll.add(R"({ "name": "Bob", "age": 30 })").execute();
mysqlx::DocResult res = coll.find("age >= :age") .bind("age", 26) .sort("age DESC") .execute();
for (mysqlx::DbDoc doc : res) { std::cout << doc << std::endl; }
coll.modify("name = 'Alice'") .set("city", "Shanghai") .execute();
coll.remove("name = 'Bob'").execute(); } catch (const mysqlx::Error &err) { std::cerr << "Error: " << err << std::endl; return 1; } return 0; }
|
完整示例:表操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <iostream> #include <mysqlx/xdevapi.h>
int main() { try { mysqlx::Session sess("localhost", 33060, "root", "password"); mysqlx::Schema db = sess.getSchema("test");
sess.sql( "CREATE TABLE IF NOT EXISTS users (" "id INT PRIMARY KEY AUTO_INCREMENT, " "name VARCHAR(50), " "age INT)" ).execute();
mysqlx::Table tab = db.getTable("users");
tab.insert("name", "age") .values("Alice", 25) .values("Bob", 30) .execute();
mysqlx::RowResult res = tab.select("id", "name", "age") .where("age > :age") .bind("age", 20) .orderBy("age DESC") .execute();
for (mysqlx::Row row : res) { std::cout << row[0] << ", " << row[1] << ", " << row[2] << std::endl; }
tab.update() .set("age", 35) .where("name = :name") .bind("name", "Bob") .execute();
tab.remove() .where("name = :name") .bind("name", "Alice") .execute(); } catch (const mysqlx::Error &err) { std::cerr << "MySQL Error: " << err << std::endl; return 1; } return 0; }
|
编译方法
g++ 示例
具体路径按你的安装位置调整:
1 2 3 4
| g++ -std=c++17 main.cpp -o app \ -I/usr/include/mysql-cppconn-8 \ -L/usr/lib \ -lmysqlcppconn8
|
有些环境库名可能不同,请以实际安装内容为准。
CMake 示例
1 2 3 4 5 6 7 8 9
| cmake_minimum_required(VERSION 3.10) project(mysqlx_demo)
set(CMAKE_CXX_STANDARD 17)
add_executable(mysqlx_demo main.cpp)
target_include_directories(mysqlx_demo PRIVATE /usr/include/mysql-cppconn-8) target_link_libraries(mysqlx_demo PRIVATE mysqlcppconn8)
|
常见注意事项
X DevAPI 走的是 33060,不是 3306
很多人连接失败就是因为端口写成了传统 MySQL 端口。
要确认 MySQL X Plugin 已开启
否则即使 MySQL 正常运行,也无法用 X DevAPI 连接。
条件表达式不是完整 SQL
例如:
find("age > 20")
where("name = :name")
这些表达式是 X DevAPI 支持的语法子集,不完全等同于随便写一整条 SQL。
JSON 文档字段路径要注意
例如创建索引时常使用:
优先使用参数绑定
不要自己拼接用户输入,避免注入问题:
1 2 3 4
| tab.select("id", "name") .where("name = :name") .bind("name", user_input) .execute();
|
自动生成 _id
Collection 中通常每个文档有 _id。
如果你不自己提供,系统可能自动生成。
常用 API 速查
连接与 schema
1 2
| mysqlx::Session sess("localhost", 33060, "root", "password"); mysqlx::Schema db = sess.getSchema("test");
|
collection
1 2 3 4 5
| auto coll = db.getCollection("c1"); coll.add(R"({"name":"A"})").execute(); coll.find("name = 'A'").execute(); coll.modify("name = 'A'").set("age", 20).execute(); coll.remove("name = 'A'").execute();
|
table
1 2 3 4 5
| auto tab = db.getTable("users"); tab.insert("name", "age").values("A", 20).execute(); tab.select("id", "name").where("age > 18").execute(); tab.update().set("age", 21).where("name='A'").execute(); tab.remove().where("name='A'").execute();
|
SQL
1
| sess.sql("SELECT * FROM users WHERE age > ?").bind(18).execute();
|
事务
1 2 3
| sess.startTransaction(); sess.commit(); sess.rollback();
|