MySQL官方C/C++ 接口入门
MySQL提供了多种方式供C/C++程序访问数据库,最常用的是MySQL官方提供的C API(也称为MySQL Connector/C)。本指南将介绍如何使用这些接口进行基本的数据库操作。
一、准备工作
安装MySQL开发库
在开始之前,你需要安装MySQL客户端库和开发文件:
Ubuntu/Debian:
bash
sudo apt-get install libmysqlclient-dev
CentOS/RHEL:
bash
sudo yum install mysql-devel
macOS (使用Homebrew):
bash
brew install mysql-client
包含头文件和链接库
在C/C++程序中,需要包含MySQL头文件:
cpp
#include <mysql/mysql.h>
编译时需要链接MySQL客户端库:
bash
gcc -o program program.c `mysql_config --cflags --libs`
# 或者
g++ -o program program.cpp `mysql_config --cflags --libs`
二、基本使用流程
1. 建立连接
cpp
#include <iostream>
#include <mysql/mysql.h>
#include <stdio.h>int main() {MYSQL *conn;const char *server = "localhost";const char *user = "your_username";const char *password = "your_password";const char *database = "your_database";// 初始化连接句柄conn = mysql_init(NULL);// 连接到数据库if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {fprintf(stderr, "%s\n", mysql_error(conn));mysql_close(conn);return 1;}std::cout << "Connected to database successfully!" << std::endl;// 执行数据库操作...// 关闭连接mysql_close(conn);return 0;
}
2. 执行查询
cpp
// 执行SQL查询
if (mysql_query(conn, "SELECT * FROM users")) {fprintf(stderr, "%s\n", mysql_error(conn));mysql_close(conn);return 1;
}// 获取结果集
MYSQL_RES *result = mysql_store_result(conn);
if (result == NULL) {fprintf(stderr, "%s\n", mysql_error(conn));mysql_close(conn);return 1;
}// 获取字段数量
int num_fields = mysql_num_fields(result);// 获取所有行
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {// 处理每一行的数据for (int i = 0; i < num_fields; i++) {printf("%s ", row[i] ? row[i] : "NULL");}printf("\n");
}// 释放结果集
mysql_free_result(result);
3. 执行插入、更新和删除操作
cpp
// 插入数据
if (mysql_query(conn, "INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')")) {fprintf(stderr, "INSERT error: %s\n", mysql_error(conn));
} else {std::cout << "Inserted successfully, affected rows: " << mysql_affected_rows(conn) << std::endl;
}// 更新数据
if (mysql_query(conn, "UPDATE users SET email='newemail@example.com' WHERE name='John Doe'")) {fprintf(stderr, "UPDATE error: %s\n", mysql_error(conn));
} else {std::cout << "Updated successfully, affected rows: " << mysql_affected_rows(conn) << std::endl;
}// 删除数据
if (mysql_query(conn, "DELETE FROM users WHERE name='John Doe'")) {fprintf(stderr, "DELETE error: %s\n", mysql_error(conn));
} else {std::cout << "Deleted successfully, affected rows: " << mysql_affected_rows(conn) << std::endl;
}
4. 使用预处理语句(防止SQL注入)
cpp
MYSQL_STMT *stmt;
MYSQL_BIND bind[2];
char name[50];
char email[100];// 创建预处理语句
stmt = mysql_stmt_init(conn);
if (mysql_stmt_prepare(stmt, "INSERT INTO users (name, email) VALUES (?, ?)", -1)) {fprintf(stderr, "Prepare error: %s\n", mysql_stmt_error(stmt));return 1;
}// 初始化绑定参数
memset(bind, 0, sizeof(bind));// 绑定name参数
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = name;
bind[0].buffer_length = sizeof(name);// 绑定email参数
bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = email;
bind[1].buffer_length = sizeof(email);// 绑定参数到语句
if (mysql_stmt_bind_param(stmt, bind)) {fprintf(stderr, "Bind error: %s\n", mysql_stmt_error(stmt));return 1;
}// 设置参数值并执行
strcpy(name, "Jane Doe");
strcpy(email, "jane@example.com");if (mysql_stmt_execute(stmt)) {fprintf(stderr, "Execute error: %s\n", mysql_stmt_error(stmt));
} else {std::cout << "Prepared statement executed successfully!" << std::endl;
}// 关闭预处理语句
mysql_stmt_close(stmt);
错误处理
始终检查每个MySQL函数调用的返回值,并使用mysql_error()
或mysql_stmt_error()
获取错误信息:
cpp
if (mysql_query(conn, "SELECT * FROM non_existent_table")) {fprintf(stderr, "Error: %s\n", mysql_error(conn));// 处理错误
}
class MySQLConnection : public MySQLBase {
public:MySQLConnection() : MySQLBase() {conn = mysql_init(nullptr);if (conn == nullptr) {throw std::runtime_error("无法初始化MySQL连接");}// 设置连接选项mysql_options(conn, MYSQL_OPT_RECONNECT, &reconnect);mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");}~MySQLConnection() {disconnect();}bool connect(const std::string& host, const std::string& user,const std::string& password, const std::string& database,unsigned int port = 3306, const char* unix_socket = nullptr,unsigned long client_flag = 0) {checkConnection();MYSQL* result = mysql_real_connect(conn, host.c_str(), user.c_str(),password.c_str(), database.c_str(),port, unix_socket, client_flag);if (result == nullptr) {unsigned int error_code = mysql_errno(conn);std::string error_msg = mysql_error(conn);// 根据错误代码进行特殊处理switch (error_code) {case CR_CONN_HOST_ERROR:throw MySQLException(error_code, mysql_sqlstate(conn),"无法连接到主机: " + host + " - " + error_msg);case CR_CONNECTION_ERROR:throw MySQLException(error_code, mysql_sqlstate(conn),"连接错误: " + error_msg);case CR_SERVER_GONE_ERROR:throw MySQLException(error_code, mysql_sqlstate(conn),"服务器连接已断开: " + error_msg);case CR_SERVER_LOST:throw MySQLException(error_code, mysql_sqlstate(conn),"服务器连接丢失: " + error_msg);case CR_ACCESS_DENIED_ERROR:throw MySQLException(error_code, mysql_sqlstate(conn),"访问被拒绝: " + user + "@" + host);default:throw MySQLException(error_code, mysql_sqlstate(conn),"连接失败: " + error_msg);}}// 设置字符集if (mysql_set_character_set(conn, "utf8mb4") != 0) {throw MySQLException(mysql_errno(conn), mysql_sqlstate(conn),"设置字符集失败: " + std::string(mysql_error(conn)));}return true;}void disconnect() {if (conn != nullptr) {mysql_close(conn);conn = nullptr;}}bool ping() {checkConnection();return mysql_ping(conn) == 0;}private:my_bool reconnect = 1; // 启用自动重连
};
三、UTF-8处理
设置客户端字符集为UTF-8
1. 连接后立即设置字符集
cpp
#include <iostream>
#include <mysql/mysql.h>
#include <cstring>int main() {MYSQL *conn = mysql_init(NULL);if (!mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0)) {std::cerr << "连接失败: " << mysql_error(conn) << std::endl;return 1;}// 设置字符集为UTF-8if (mysql_set_character_set(conn, "utf8mb4")) {std::cerr << "设置字符集失败: " << mysql_error(conn) << std::endl;mysql_close(conn);return 1;}std::cout << "字符集设置为: " << mysql_character_set_name(conn) << std::endl;mysql_close(conn);return 0;
}
2. 在连接选项中指定字符集
cpp
MYSQL *conn = mysql_init(NULL);// 设置连接选项
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");
mysql_options(conn, MYSQL_INIT_COMMAND, "SET NAMES utf8mb4");if (!mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0)) {std::cerr << "连接失败: " << mysql_error(conn) << std::endl;return 1;
}
完整的UTF-8处理示例
#include <iostream>
#include <mysql/mysql.h>
#include <cstring>
#include <string>class MySQLUTF8Handler {
private:MYSQL *conn;public:MySQLUTF8Handler() : conn(nullptr) {}~MySQLUTF8Handler() {disconnect();}bool connect(const std::string& host, const std::string& user, const std::string& password, const std::string& database) {conn = mysql_init(nullptr);if (!conn) {std::cerr << "初始化MySQL失败" << std::endl;return false;}// 设置字符集选项mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");if (!mysql_real_connect(conn, host.c_str(), user.c_str(), password.c_str(), database.c_str(), 0, nullptr, 0)) {std::cerr << "连接失败: " << mysql_error(conn) << std::endl;return false;}// 确保字符集设置成功if (mysql_set_character_set(conn, "utf8mb4")) {std::cerr << "设置字符集失败: " << mysql_error(conn) << std::endl;return false;}std::cout << "成功连接到数据库,字符集: " << mysql_character_set_name(conn) << std::endl;return true;}void disconnect() {if (conn) {mysql_close(conn);conn = nullptr;}}bool createTable() {const char* query = "CREATE TABLE IF NOT EXISTS multilingual (""id INT AUTO_INCREMENT PRIMARY KEY, ""chinese_text VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, ""japanese_text VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, ""korean_text VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, ""russian_text VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci) ""ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";if (mysql_query(conn, query)) {std::cerr << "创建表失败: " << mysql_error(conn) << std::endl;return false;}return true;}bool insertMultilingualData(const std::string& chinese, const std::string& japanese,const std::string& korean, const std::string& russian) {// 使用预处理语句防止SQL注入并正确处理UTF-8MYSQL_STMT *stmt = mysql_stmt_init(conn);if (!stmt) {std::cerr << "初始化预处理语句失败" << std::endl;return false;}const char* query = "INSERT INTO multilingual (chinese_text, japanese_text, korean_text, russian_text) ""VALUES (?, ?, ?, ?)";if (mysql_stmt_prepare(stmt, query, strlen(query))) {std::cerr << "准备语句失败: " << mysql_stmt_error(stmt) << std::endl;mysql_stmt_close(stmt);return false;}MYSQL_BIND bind[4];memset(bind, 0, sizeof(bind));// 绑定中文参数bind[0].buffer_type = MYSQL_TYPE_STRING;bind[0].buffer = (void*)chinese.c_str();bind[0].buffer_length = chinese.length();bind[0].length = &bind[0].buffer_length;// 绑定日文参数bind[1].buffer_type = MYSQL_TYPE_STRING;bind[1].buffer = (void*)japanese.c_str();bind[1].buffer_length = japanese.length();bind[1].length = &bind[1].buffer_length;// 绑定韩文参数bind[2].buffer_type = MYSQL_TYPE_STRING;bind[2].buffer = (void*)korean.c_str();bind[2].buffer_length = korean.length();bind[2].length = &bind[2].buffer_length;// 绑定俄文参数bind[3].buffer_type = MYSQL_TYPE_STRING;bind[3].buffer = (void*)russian.c_str();bind[3].buffer_length = russian.length();bind[3].length = &bind[3].buffer_length;if (mysql_stmt_bind_param(stmt, bind)) {std::cerr << "绑定参数失败: " << mysql_stmt_error(stmt) << std::endl;mysql_stmt_close(stmt);return false;}if (mysql_stmt_execute(stmt)) {std::cerr << "执行语句失败: " << mysql_stmt_error(stmt) << std::endl;mysql_stmt_close(stmt);return false;}mysql_stmt_close(stmt);return true;}void queryAndDisplayData() {const char* query = "SELECT * FROM multilingual";if (mysql_query(conn, query)) {std::cerr << "查询失败: " << mysql_error(conn) << std::endl;return;}MYSQL_RES *result = mysql_store_result(conn);if (!result) {std::cerr << "获取结果失败: " << mysql_error(conn) << std::endl;return;}int num_fields = mysql_num_fields(result);MYSQL_ROW row;std::cout << "\n查询结果:" << std::endl;std::cout << "==========================================" << std::endl;while ((row = mysql_fetch_row(result))) {std::cout << "ID: " << (row[0] ? row[0] : "NULL") << std::endl;std::cout << "中文: " << (row[1] ? row[1] : "NULL") << std::endl;std::cout << "日文: " << (row[2] ? row[2] : "NULL") << std::endl;std::cout << "韩文: " << (row[3] ? row[3] : "NULL") << std::endl;std::cout << "俄文: " << (row[4] ? row[4