MySQL Connector/C API的使用

目录

前言

一些API的体验

创建MySQL对象

连接数据库

关闭数据库连接

下发SQL请求

统一编码格式

获取查询结果

实际示例

题外话:图形化界面

尾声


前言

ok,我们来到了mysql基础的最后一篇,其实我也没有想到我的mysql的博客会比网络先更完,明明网络是更早学的qwq,主要还是网络后面复习需要一些时间,没mysql复习的这么快吧,当然这个专栏可能后面还会在我继续学了mysql更深层次的一些内容后继续更新,话不多说,让我们开始mysql基础的最后一篇的旅程

我们之前一直都是在用命令行来操作数据库,今天我们换一种方式来操作,用编程语言!

配置的话也非常简单,几行命令就解决啦

bash 复制代码
# 下载库文件
sudo apt-get install libmysqlclient-dev   
sudo apt-get install libmysqlcppconn-dev
​
# 查看头文件路径
dpkg -L libmysqlclient-dev

一些API的体验

首先在使用这些api之前肯定是要包含一下对应的头文件的------ #include <mysql/mysql.h>

然后在编译时要带上 -L/usr/lib64/mysql/ 和 -lmysqlclient 让系统知道要连的是在/usr/lib64/mysql/路径下的mysqlclient库

创建MySQL对象

在连接数据库之前,需要先创建一个MySQL对象,创建MySQL对象的函数如下:

cpp 复制代码
MYSQL* mysql_init(MYSQL *mysql);
  • 该函数用来分配或者初始化一个 MySQL 对象,用于连接 MySQL 服务器。

  • 如果传入的参数是 nullptr ,那么 mysql_init 将自动为你分配一个 MySQL 对象并返回。

  • 如果传入的参数是一个地址,那么 mysql_init 将在该地址处帮你完成初始化。

MYSQL 对象中包含了各种信息,其类型定义如下:

cpp 复制代码
typedef struct MYSQL {
  NET net;                     /* Communication parameters */
  unsigned char *connector_fd; /* ConnectorFd for SSL */
  char *host, *user, *passwd, *unix_socket, *server_version, *host_info;
  char *info, *db;
  struct CHARSET_INFO *charset;
  MYSQL_FIELD *fields;
  struct MEM_ROOT *field_alloc;
  uint64_t affected_rows;
  uint64_t insert_id;      /* id if insert on table with NEXTNR */
  uint64_t extra_info;     /* Not used */
  unsigned long thread_id; /* Id for connection in server */
  unsigned long packet_length;
  unsigned int port;
  unsigned long client_flag, server_capabilities;
  unsigned int protocol_version;
  unsigned int field_count;
  unsigned int server_status;
  unsigned int server_language;
  unsigned int warning_count;
  struct st_mysql_options options;
  enum mysql_status status;
  enum enum_resultset_metadata resultset_metadata;
  bool free_me;   /* If free in mysql_close */
  bool reconnect; /* set to 1 if automatic reconnect */
​
  /* session-wide random string */
  char scramble[SCRAMBLE_LENGTH + 1];
​
  LIST *stmts; /* list of all statements */
  const struct MYSQL_METHODS *methods;
  void *thd;
  /*
    Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flag
    from mysql_stmt_close if close had to cancel result set of this object.
  */
  bool *unbuffered_fetch_owner;
  void *extension;
} MYSQL;
  • MYSQL对象中的 methods 变量是一个结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。

连接数据库

创建完 MySQL 对象后就可以连接数据库了,连接数据库的函数如下:

cpp 复制代码
MYSQL *STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
                                  const char *user, const char *passwd,
                                  const char *db, unsigned int port,
                                  const char *unix_socket,
                                  unsigned long clientflag);

参数说明:

  • mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。

  • host: 表示需要连接的 MySQL 服务器的IP地址, "127.0.0.1" 表示连接本地 MySQL 服务器。

  • user: 表示连接 MySQL 服务器时,所使用用户的用户名。

  • passwd: 表示连接 MySQL 服务器时,所使用用户的密码

  • db: 表示连接 MySQL 服务器后,需要使用的数据库。

  • port: 表示连接的 MySQL 服务器,所对应的端口号。

  • unix_socket: 表示连接时应该使用的套接字或命名管道,通常设置为 NULL 。

  • clientflag: 可以设置为多个标志位的组合,表示允许特定的功能,通常设置为0。

返回值说明:

  • 如果连接数据库成功,则返回一个 MySQL 对象,该对象与第一个参数的值相同。

  • 如果连接数据库失败,则返回 NULL 。

关闭数据库连接

与数据库交互完毕后,需要关闭数据库连接,关闭数据库连接的函数如下

cpp 复制代码
void mysql_close(MYSQL *mysql);
  • 该函数的参数,就是连接数据库前调用 mysql_init 创建的 MySQL 对象。

  • 如果传入的 MySQL 对象是 mysql_init 自动创建的,那么调用 mysql_close 时就会释放这个对象。

下发SQL请求

与数据库建立连接期间,就可以向 MySQL 服务器下发 SQL 请求,下发 SQL 请求的函数如下:

cpp 复制代码
int mysql_query(MYSQL *mysql, const char *q);

参数说明:

  • mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。

  • q: 表示向MySQL服务器下发的 SQL 请求,SQL 最后可以不带分号。

返回值说明:

  • 返回值为0表示 SQL 执行成功,否则表示 SQL 执行失败。

统一编码格式

在连接数据库之后,需要统一客户端和服务器的编码格式(客户端默认是latin1拉丁),避免在数据交互过程中出现乱码,设置编码格式的函数如下:

cpp 复制代码
int mysql_set_character_set(MYSQL *mysql, const char *csname);

参数说明:

  • mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。

  • csname: 表示要设置的编码格式,如 " utf8 " 。

返回值说明:

  • 返回值为0表示设置成功,否则表示设置失败。

获取查询结果

获取查询结果的函数如下:

cpp 复制代码
MYSQL_RES* mysql_store_result(MYSQL *mysql);
  • 该函数会调用指定 MySQL 对象中对应的函数指针来获取查询结果,并将获取到的查询结果保存到 MYSQL_RES 变量中进行返回。

  • 成功返回查询数据的起始地址,失败返回空nullptr

  • 需要注意的是,MYSQL_RES 变量的内存空间是 malloc 出来的,因此在使用完后需要调用 free 函数进行释放,否则会造成内存泄露

cpp 复制代码
typedef struct MYSQL_RES {
  uint64_t row_count;
  MYSQL_FIELD *fields;
  struct MYSQL_DATA *data;
  MYSQL_ROWS *data_cursor;
  unsigned long *lengths; /* column lengths of current row */
  MYSQL *handle;          /* for unbuffered reads */
  const struct MYSQL_METHODS *methods;
  MYSQL_ROW row;         /* If unbuffered read */
  MYSQL_ROW current_row; /* buffer to current row */
  struct MEM_ROOT *field_alloc;
  unsigned int field_count, current_field;
  bool eof; /* Used by mysql_fetch_row */
  /* mysql_stmt_close() had to cancel this result */
  bool unbuffered_fetch_cancelled;
  enum enum_resultset_metadata metadata;
  void *extension;
} MYSQL_RES;

这里不要使用原生的free或者delete来进行释放,而是使用mysql给我们提供的**mysql_free_result(MYSQL_RES* res);**接口进行释放

可以这样来理解res:

获取查询结果的行数的函数如下:

cpp 复制代码
my_ulonglong mysql_num_rows(MYSQL_RES *res);

\^\]: 这个my_ulonglong其实就是:typedef uint64_t my_ulonglong; 获取查询结果的列数的函数如下: ```cpp unsigned int mysql_num_fields(MYSQL_RES *res); ``` 获取查询结果中的一行数据的函数如下: ```cpp MYSQL_ROW mysql_fetch_row(MYSQL_RES *result); ``` 它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char \*\*,遍历时会自动获取遍历到当前行的行数据(因为每次循环会自动向后移动指向下一行),其变量就相对于字符串数组,可以下标访问改行各列元素 ![image-20251126113652481](https://i-blog.csdnimg.cn/img_convert/cc1adea67f668871541c9e6c208a37a3.png) 获取查询结果的列属性的函数如下: ```cpp MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES *res); ``` 其实这个MYSQL_FIELD也是一个结构体类型,其中都是列属性 ```cpp typedef struct MYSQL_FIELD { char *name; /* Name of column */ char *org_name; /* Original column name, if an alias */ char *table; /* Table of column if column was a field */ char *org_table; /* Org table name, if table was an alias */ char *db; /* Database for table */ char *catalog; /* Catalog for table */ char *def; /* Default value (set by mysql_list_fields) */ unsigned long length; /* Width of column (create length) */ unsigned long max_length; /* Max width for selected set */ unsigned int name_length; unsigned int org_name_length; unsigned int table_length; unsigned int org_table_length; unsigned int db_length; unsigned int catalog_length; unsigned int def_length; unsigned int flags; /* Div flags */ unsigned int decimals; /* Number of decimals in field */ unsigned int charsetnr; /* Character set */ enum enum_field_types type; /* Type of field. See mysql_com.h for types */ void *extension; } MYSQL_FIELD; ``` #### 实际示例 我们现在来一个实际例子来用一下上面了解到的相关接口,现在登录一个账户 mochu 并且使用数据库 conn 再查询表 user ![image-20251125210303455](https://i-blog.csdnimg.cn/img_convert/2d7b28a3001ea155be01edbe3b14f7ce.png) 然后我们要编写一段代码来将查询的这个表中内容输出到屏幕上 ```cpp #include #include ​ const std::string host = "127.0.0.1"; const std::string user = "mochu"; const std::string password = "123456"; const std::string dbname = "conn"; const unsigned int port = 3306; ​ int main() { // 1.初始化全局的mysql对象 // MYSQL*就相对于文件部分的FLIE* ,就是句柄 MYSQL *mysql = mysql_init(nullptr); if (mysql == nullptr) { std::cerr << "init MYSQL error" << std::endl; return 1; } ​ // 2.连接数据库 if (mysql_real_connect(mysql, host.c_str(), user.c_str(), password.c_str(), dbname.c_str(), port, nullptr, 0) == 0) { std::cerr << "connect MYSQL error" << std::endl; return 2; } std::cout << "connect MYSQL success" << std::endl; ​ // 3.设置一下字符集防止乱码 if (mysql_set_character_set(mysql, "utf8")) { std::cerr << "set_character error" << std::endl; return 3; } std::cout << "set_character success" << std::endl; ​ // 4.下发mysql命令 // std::string sql = "update user set name='李四' where id=2"; std::string sql = "select * from user"; // std::string sql = "insert into user (name,age,telphone) values('王五',21,13433322)"; int n = mysql_query(mysql, sql.c_str()); if (n == 0) std::cout << sql << " success" << std::endl; else std::cout << sql << " failed" << std::endl; ​ // 5.获取查询结果到查询集res当中 MYSQL_RES *res = mysql_store_result(mysql); if (res == nullptr) { std::cerr << "mysql_store_result error" << std::endl; return 4; } ​ // 6.获取其行列信息(有多少行,多少列) my_ulonglong rows = mysql_num_rows(res); my_ulonglong fields = mysql_num_fields(res); std::cout << "行: " << rows << std::endl; std::cout << "列: " << fields << std::endl; ​ // 7.打印列属性 MYSQL_FIELD *fields_array = mysql_fetch_field(res); for (my_ulonglong i = 0; i < fields; i++) { // 该结构体中的name成员就是列名称 std::cout << fields_array[i].name << "\t"; } std::cout << std::endl; ​ // 8.打印结果 for (my_ulonglong i = 0; i < rows; i++) { // 获取一行的数据 MYSQL_ROW row = mysql_fetch_row(res); for (my_ulonglong j = 0; j < fields; j++) { //row[j] = *(row+j) std::cout << row[j] << "\t"; } std::cout << std::endl; } ​ // 9.释放关闭工作 // delete res; // 使用其对应的释放关闭接口 mysql_free_result(res); mysql_close(mysql); return 0; } ``` 接着 make 编译以下,运行 ./mytest,查询结果如下: ![image-20251126113107331](https://i-blog.csdnimg.cn/img_convert/92cccee43a4ec299abb0043390f75d01.png) #### 题外话:图形化界面 其实,还可以考虑用 图形化GUI页面 来操作,这里推荐Navicat,Navicat在我学mysql之前做项目时是用过的,好像记得是要收费的,但是有学习版的(大家可以搜搜博客啥的),我这个就是学习版的,用起来其实比命令行或者api要简单容易上手很多,但是肯定就只停留在用的层面啦,理解原理还得是命令行代码\~,理解之后使用图形化界面方式来操作就很舒服直观了 ![image-20251126115659003](https://i-blog.csdnimg.cn/img_convert/cf61b0aec3c05cf34e9a566e305db371.png) 其界面呢就是这样的: ![image-20251126120201347](https://i-blog.csdnimg.cn/img_convert/946b473cfe8368eaefc4db5de66033d4.png) 其实经过mysql的系统学习,使用这个图形化界面那真的就是小意思啦,各种功能都是非常清楚的! 总结:其实这个图形化界面就和我们写的c++式的客户端差不多的,只是从代码转为了鼠标图形化操作 ### 尾声 ok,目前mysql的基础我们已经全部了解啦,目前mysql专栏的博客就要告一段落了,但是其中的很多内容我还是需要去反复复习的,大家也是需要去不断复习一下的,特别是sql语句的编写以及mysql的索引和事务相关的内容都是很重要的,这一篇的话就是说要用到的时候来查一查就基本上可以使用到代码当中了,这种api接口没有什么需要死记硬背的\~

相关推荐
霖霖总总2 小时前
[Redis小技巧15]Redis AOF 重写与混合持久化深度解析:从原理到生产实践
数据库·redis
moxiaoran57532 小时前
MySQL分库分表的实现(一)
数据库·mysql
Y001112362 小时前
Day6-MySQL-函数
数据库·sql·mysql
召田最帅boy2 小时前
使用自定义图片作为Emoji表情的技术实现
数据库·html
2401_853576502 小时前
使用PyTorch构建你的第一个神经网络
jvm·数据库·python
Nandeska3 小时前
6、认识和使用Redis Stack
java·数据库·redis
V1ncent Chen3 小时前
SQL大师之路 09 模式匹配(正则表达式)
数据库·sql·mysql·正则表达式·数据分析
SelectDB技术团队3 小时前
Apache Doris + SelectDB:定义 AI 时代,实时分析的三大范式
数据库·数据仓库·人工智能·云原生·实时分析
weixin_704266053 小时前
事务管理全解析:从ACID到Spring实现
java·数据库·spring