使用C语言连接MySQL

库的准备

要使用C语言连接mysql,需要使用mysql官网提供的connect库,可以去官网下载,由于我们要下载到 Linux 操作系统中,也可以使用如下指令进行安装库

bash 复制代码
sudo apt-get install libmysqlclient-dev

MySQL连接C/C++的库通常会安装在/usr/include/mysql目录下,您可以通过以下命令检查该目录下是否存在相关的头文件:

bash 复制代码
ls /usr/include/mysql

库文件通常会安装在/usr/lib/usr/lib64目录下,您可以通过以下命令检查该目录下是否存在相关的库文件:

bash 复制代码
ls /usr/lib/mysql
ls /usr/lib64/mysql

不过这只是一般的情况,根据版本的不同机器的不同都有差异,其库文件安装的位置也不同,如果安装在非标准路径下,可以使用mysql_config命令来获取正确的编译选项,从而了解到库文件安装的位置:

bash 复制代码
mysql_config --cflags --libs

我的机器是Ubuntu系统,从显示的结果我们可以看出 -L 后跟着的是 /usr/lib/x86_64-linux-gnu,说明库文件位于/usr/lib/x86_64-linux-gnu下,由于其中文件过多就不展示,实际上我们编译时也可以直接使用 -L /usr/lib 。
现在我们 尝试链接mysql client,通过 mysql_get_client_info() 函数,来验证我们的引入是否成功。

cpp 复制代码
#include<iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
    cout<< "mysql version:" << mysql_get_client_info() <<endl;
}

编译指令如下:

bash 复制代码
 g++ -o mytest testdb.cc -L /usr/lib -l mysqlclient

其中 -L 后指明了动态库的路径,-l 跟着所要链接的动态库,由于我们在包含头文件时写的是#include <mysql/mysql.h> ,所以不用再指明头文件的具体路径,因为头文件位于 /usr/include/mysql 路径下,而 /usr/include 已经添加到环境变量PATH中,如果包含头文件时写的是#include <mysql.h>,则编译时需要添加 -I /usr/include/mysql ,指明头文件所在路径。

运行结果如下,说明我们已经下载好MySQL连接C/C++的库。

mysql****接口介绍

mysql_init

cpp 复制代码
MYSQL *mysql_init(MYSQL *mysql);

该函数用于初始化一个MySQL连接对象。
第一个参数 MYSQL 是 C api中一个非常重要的变量,里面内存非常丰富,有 port,dbname,charset等连接基本参数。

  • 如果mysql是NULL指针,该函数将分配、初始化、并返回新对象。
  • 如果mysql不是NULL指针,该函数将初始化对象,并返回对象的地址。
cpp 复制代码
MYSQL* conn = mysql_create_conn(NULL);

mysql_real_connect

cpp 复制代码
MYSQL *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 client_flag);

初始化完毕之后,必须先链接数据库,在进行后续操作。(mysql网络部分是基于TCP/IP的)mysql_real_connect用于尝试与运行在主机上的MySQL数据库引擎建立连接。在能够执行需要有效MySQL连接句柄结构的任何其他API函数之前,mysql_real_connect必须成功完成。

  • mysql:这应该是一个已经初始化的MYSQL结构的地址。在调用mysql_real_connect之前,必须调用mysql_init来初始化MYSQL结构。
  • host:主机名或IP地址。如果hostNULL或字符串"localhost",连接将被视为与本地主机的连接。
  • user:用户的MySQL登录ID。如果userNULL或空字符串"",用户将被视为当前用户。
  • passwd:用户的密码。
  • db:数据库名称。如果dbNULL,连接会将默认的数据库设为该值。
  • port:如果不是0,其值将用作TCP/IP连接的端口号。注意,host参数决定了连接的类型。
  • unix_socket:如果不是NULL,该字符串描述了应使用的套接字或命名管道。注意,host参数决定了连接的类型。
  • client_flag:通常为0,但也能设置为特定标志的组合,以允许特定功能,如使用压缩协议、返回发现的行数而非受影响的行数等。

我们可以先使用如下代码来查看是否连接成功,该文件为 testdb.cc

cpp 复制代码
#include<iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
    MYSQL* conn=mysql_init(nullptr);   
    if(conn==nullptr)
        cout<<"mysql_init error"<<endl;
    //链接数据库
    mysql_real_connect(conn,"localhost","lbk","2162627569","connect",3306,nullptr,0);
    if(conn==nullptr)
        cout<<"mysql_real_connect error"<<endl;
    else
        cout<<"mysql_real_connect success"<<endl;
    return 0;
}

编译指令

bash 复制代码
g++ -o mytest testdb.cc -L /usr/lib -l mysqlclient

我们可以看到连接成功。

mysql_query

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

参数:

  • mysql:一个已经初始化的MYSQL对象,表示与MySQL数据库的连接。
  • query:一个以空字符结尾的字符串,包含了要发送的SQL查询语句。

返回值:如果查询成功,函数返回0;如果发生错误,函数返回非零值。

例如我们向connect数据库中的stu表中插入数据

cpp 复制代码
#include <iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
    MYSQL *conn = mysql_init(nullptr);
    if (conn == nullptr)
        cout << "mysql_init error" << endl;
    // 链接数据库
    mysql_real_connect(conn, "localhost", "lbk", "2162627569", "connect", 3306, nullptr, 0);
    if (conn == nullptr)
        cout << "mysql_real_connect error" << endl;
    // 执行sql语句
    const char *sql = "insert into stu values(1,'Tom')";
    if (mysql_query(conn, sql) == 0)
        cout << "insert success" << endl;
    return 0;
}

运行程序后,我们可以在MySQL中看到stu表中插入的数据。

mysql_store_result

sql 执行完以后,如果是查询语句,我们当然还要读取数据,如果 update , insert等语句,那么就看下操作成功与否即可。我们就需要使用select语句来获取查询结果: 如果mysql_query返回成功,那么我们就通过mysql_store_result这个函数来读取结果。原型如下:

cpp 复制代码
MYSQL_RES *mysql_store_result(MYSQL *mysql);

该函数将查询的全部结果读取到客户端,分配一个MYSQL_RES结构,并将结果置于该结构中,如果读取结果集失败,mysql_store_result也会返回Null指针。以下是 MYSQL_RES结构体的定义:

cpp 复制代码
typedef struct st_mysql_res {
    my_ulonglong row_count;  // 结果集的行数
    unsigned int field_count, current_field;  // 结果集的列数和当前列
    MYSQL_FIELD *fields;  // 结果集的列信息
    MYSQL_DATA *data;  // 结果集的数据
    MYSQL_ROWS *data_cursor;  // 结果集的光标
    MEM_ROOT field_alloc;  // 内存结构
    MYSQL_ROW row;  // 非缓冲的时候用到
    MYSQL_ROW current_row;  // mysql_store_result 时会用到,当前行
    unsigned long *lengths;  // 每列的长度
    MYSQL *handle;  // mysql_use_result 会用
    my_bool eof;  // 是否为行为
} MYSQL_RES;

获得了结果后,我们可以接着调用以下函数来处理结果。

cpp 复制代码
my_ulonglong mysql_num_rows(MYSQL_RES *res);//获取结果行数
unsigned int mysql_num_fields(MYSQL_RES *res);//获取结果列数
mysql_fetch_fields
cpp 复制代码
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);//获取列的属性

MYSQL_FIELD 结构体是 MySQL C API 中用于表示查询结果集中的字段信息的结构体。它包含了字段的名称、类型、长度等元数据信息。以下是 MYSQL_FIELD 结构体的定义:

cpp 复制代码
typedef struct st_mysql_field {
    char *name; /* 字段名 */
    char *org_name; /* 原始字段名,如果有别名 */
    char *table; /* 字段所属的表名,如果字段是表中的一个字段 */
    char *org_table; /* 原始表名,如果表名有别名 */
    char *db; /* 表所在的数据库名 */
    char *catalog; /* 表的目录名 */
    char *def; /* 字段的默认值 */
    unsigned long length; /* 字段的长度 */
    unsigned long max_length; /* 字段在结果集中的最大长度 */
    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; /* 字段的标志 */
    unsigned int decimals; /* 字段的小数位数 */
    unsigned int charsetnr; /* 字段的字符集编号 */
    enum enum_field_types type; /* 字段的类型 */
    void *extension;
} MYSQL_FIELD;

使用案例,列出stu表的列名:

cpp 复制代码
#include <iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
    MYSQL *conn = mysql_init(nullptr);
    if (conn == nullptr)
        cout << "mysql_init error" << endl;
    // 链接数据库
    mysql_real_connect(conn, "localhost", "lbk", "2162627569", "connect", 3306, nullptr, 0);
    if (conn == nullptr)
        cout << "mysql_real_connect error" << endl;
    // 执行sql语句
    // const char *sql = "insert into stu values(1,'Tom')";
    const char *sql1 = "insert into stu values(2,'Jane')";
    mysql_query(conn, sql1);
    const char *sql2 = "insert into stu values(3,'Jake')";
    mysql_query(conn, sql2);
    const char *sql3 = "select * from stu";
    mysql_query(conn, sql3);
    MYSQL_RES *res = mysql_store_result(conn);
    int fnum = mysql_num_fields(res);
    MYSQL_FIELD *field = mysql_fetch_fields(res);
    for (int i = 0; i < fnum; i++)
    {
        cout << field[i].name << " ";
    }
    cout << endl;
    return 0;
}

结果如下:



如果我们需要列的更多属性,可以按照结构体中的内容找出。

mysql_fetch_row
cpp 复制代码
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

MYSQL_ROW结构体在 MySQL C API 中用于表示查询结果集中的一行数据。它实际上是一个指向字符串数组的指针,其中每个字符串对应结果集中的一个字段值。以下是 MYSQL_ROW 结构体的定义:

cpp 复制代码
typedef char **MYSQL_ROW;

MYSQL_ROW 结构体没有显式定义的成员变量,因为它本质上是一个二级指针,指向一个字符串数组。数组中的每个元素都是一个以 null 结尾的字符串,代表结果集中的一个字段值。

mysql_close

cpp 复制代码
void mysql_close(MYSQL *mysql);

mysql_close函数用于关闭与MySQL数据库的连接。这个函数是MySQL C API的一部分,通常在完成数据库操作后调用,以释放与数据库连接相关的资源。

相关推荐
秃头摸鱼侠5 分钟前
MySQL查询语句(续)
数据库·mysql
MuYiLuck13 分钟前
【redis实战篇】第八天
数据库·redis·缓存
睡觉待开机14 分钟前
6. MySQL基本查询
数据库·mysql
大熊猫侯佩1 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(三)
数据库·swiftui·swift
大熊猫侯佩1 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(二)
数据库·swiftui·swift
大熊猫侯佩1 小时前
用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化
数据库·swiftui·swift
大熊猫侯佩1 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
数据库·swiftui·swift
Ares-Wang1 小时前
负载均衡LB》》HAproxy
运维·数据库·负载均衡
AI.NET 极客圈1 小时前
.NET 原生驾驭 AI 新基建实战系列(四):Qdrant ── 实时高效的向量搜索利器
数据库·人工智能·.net
weixin_470880262 小时前
MySQL体系架构解析(二):MySQL目录与启动配置全解析
数据库·mysql·面试·mysql体系架构·mysql bin目录