使用C语言连接MySQL

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 使用C语言连接MySQL

一、引入库

1.1 下载库文件

要使用C语言连接MySQL,需使用MySQL官网提供的库


MySQL :: Download Connector/C++

https://dev.mysql.com/downloads/connector/cpp/


b4089d1f9f3d42859ed9537f997ad285.png


上传到云服务器


下载完毕后将其上传到云服务器即可。下面将下载的库文件解压后存放在一个名为makeuse的目录中


28a0f7b0a97446c3ad2f6a9efe07a161.png


进入解压后的目录中,可以看到有一个include子目录和一个lib子目录


fe8e5346183d47e389f7c3de9958623c.png


include目录下存放的是一批头文件


5f3916d68f4d4bf6b79688914449fe00.png


bin目录下存放的是动静态库


6054dc14d0c04617ba45995e3430a193.png


1.2 在项目中引入库

为了方便在项目中使用刚才的库文件,可以在项目目录下创建两个软连接,分别连接到刚才的include目录和lib目录



cacedab3cf0a4d5ea78b74b3eb693d52.png

此时在项目目录下,就能直接看到刚才include和lib目录下的内容


cd5aa7e3d66a432bbcf7cc6bf247234a.png


下面先通过调用mysql_get_client_info来判断库是否引入成功,该函数的作用就是获取客户端的版本信息

#include <iostream>
#include <mysql.h>
using namespace std;
int main()
{
    //获取客户端的版本信息
    cout<<"mysql client version: "<<mysql_get_client_info()<<endl;
    return 0;
}

为了方便后续重复编译源文件,在项目目录下创建一个makefile

mysqlConnect:mysqlConnect.cc
  g++ $^ -o $@ -std=c++11 -I./include -L./lib -lmysqlclient
.PHONY:clean
clean:
  rm -rf mysqlConnect 

-I:指明头文件的搜索路径

-L:指明库文件的搜索路径

-l:指明需要连接库文件路径下的哪一个库

makefile编写完毕后,使用make命令编译代码生成可执行程序


6633902b46514538b6c7be8086382ba1.png


但此时生成的可执行程序还不能直接运行,通过ldd命令可以发现,该可执行程序所依赖的mysqlclient库找不到


452a35dec1e54cd18ac99f4bce698ecd.png


gcc/g++编译器默认都是动态链接,编译代码时默认使用动态库,所以生成的可执行程序在运行时需要找到对应的动态库进行链接,而使用的mysqlclient库并不在系统的搜索路径下

Makefile中的-I,-L和-l这三个选项,只是在编译期间告诉编译器头文件和库文件在哪里,而可执行程序生成后就与编译器无关了

动态库如何使用,在《Linux动静态库》这篇文章中讲解过,不知道如何配置的可以参考下面这篇文章


(28条消息) Linux动静态库_GG_Bond19的博客-CSDN博客

https://blog.csdn.net/GG_Bruse/article/details/128810497

配置完成后可执行程序所依赖的mysqlclient库就能够被找到了


ffced7df4e7f468d98075edf635e885b.png


运行可执行程序后,可以看到客户端的版本为6.1.11,即刚才下载的库文件的版本

43ed674b15a94280b795561ee540f6d8.png



二、使用库

2.1 连接数据库

创建MySQL对象

MYSQL* mysql_init(MYSQL *mysql);

该函数用来分配或者初始化一个MySQL对象,用于连接MySQL服务器

若传入的参数是NULL,那么mysql_init将自动为你分配一个MySQL对象并返回

若传入的参数是一个地址,那么mysql_init将在该地址处完成初始化

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

typedef struct st_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_st *charset;
    MYSQL_FIELD *fields;
    MEM_ROOT field_alloc;
    my_ulonglong affected_rows;
    my_ulonglong insert_id;   /* id if insert on table with NEXTNR */
    my_ulonglong 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;
    my_bool free_me;    /* If free in mysql_close */
    my_bool reconnect;    /* set to 1 if automatic reconnect */
    /* session-wide random string */
    char scramble[SCRAMBLE_LENGTH+1];
    my_bool unused1;
    void *unused2, *unused3, *unused4, *unused5;
    LIST *stmts;                     /* list of all statements */
    const struct st_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.
    */
    my_bool *unbuffered_fetch_owner;
    /* needed for embedded server - no net buffer to store the 'info' */
    char *info_buffer;
    void *extension;
} MYSQL;


注意:MYSQL对象中的methods变量是一个结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用


连接数据库

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 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

关闭数据库连接

void mysql_close(MYSQL *sock);

该函数的参数,就是连接数据库前调用mysql_init创建的MySQL对象

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

2.2 SQL请求

下发SQL请求

int mysql_query(MYSQL *mysql, const char *q);

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

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

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


设置编码格式


连接数据库后,需统一客户端和服务器的编码格式,避免在数据交互过程中出现乱码

int mysql_set_character_set(MYSQL *mysql, const char *csname);

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

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

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


2.3 获取查询结果

对数据库中的数据进行增删改操作时,都只需调用mysql_query向服务器下发对应的SQL请求

而对数据库中的数据进行查询操作时,除了需要调用mysql_query向服务器下发对应的查询SQL,还需获取查询结果

获取查询结果


         

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

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

typedef struct st_mysql_res {
  my_ulonglong  row_count;
  MYSQL_FIELD *fields;
  MYSQL_DATA  *data;
  MYSQL_ROWS  *data_cursor;
  unsigned long *lengths;   /* column lengths of current row */
  MYSQL   *handle;    /* for unbuffered reads */
    const struct st_mysql_methods *methods;
    MYSQL_ROW row;      /* If unbuffered read */
    MYSQL_ROW current_row;    /* buffer to current row */
    MEM_ROOT  field_alloc;
    unsigned int  field_count, current_field;
    my_bool eof;      /* Used by mysql_fetch_row */
    /* mysql_stmt_close() had to cancel this result */
    my_bool       unbuffered_fetch_cancelled;
    void *extension;
} MYSQL_RES;


获取查询结果的行数


该函数会从指定的MYSQL_RES对象中,获取查询结果的行数

unsigned int mysql_num_fields(MYSQL_RES *res);

获取查询结果的列数


该函数会从指定的MYSQL_RES对象中,获取查询结果的列数

MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES *res);

获取查询结果的列属性


该函数会从指定的MYSQL_RES对象中,获取查询结果的列属性


MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES *res);

mysql_fetch_fields函数将会返回多个MYSQL_FIELD对象,每个MYSQL_FIELD对象中保存着对应列的各种列属性,其类型定义如下:

typedef struct st_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;


获取查询结果中的一行数据


MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

MYSQL_ROW对象中保存着一行数据,这一行数据中可能包含多个字符串,对应就是这行数据中的多个列信息,因此MYSQL_ROW本质就是char**类型,其类型定义如下:


typedef char **MYSQL_ROW;   /* return data as array of strings */

2.4 使用案例

查询user表中的数据并进行打印输出

80328bc7546845b898c4463a7995e4fd.png

#include <iostream>
#include <string>
#include <mysql.h>
using namespace std;
const string host = "43.139.44.157";
const string passwd = "123qwe@@@QWE";
const string user = "bjy";
const string db = "olinejudge";
const int port = 3306;
int main()
{
    //1、获取MySQL实例(相当于创建了一个MySQL句柄)
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr) {
        cerr<<"数据库连接失败!"<<endl;
        return 1;
    }
    cout<<"数据库连接成功!"<<endl;
    mysql_set_character_set(ms, "utf8"); //设置编码格式为utf8
    //3、查询数据库表中的记录
    //a、执行查询语句
    string sql = "select * from user";
    if(mysql_query(ms, sql.c_str()) != 0) {
        cout<<"查询数据失败!"<<endl;
        return 2;
    }
    cout<<"查询数据成功!"<<endl;
    //b、获取查询结果
    MYSQL_RES* res = mysql_store_result(ms);
    int rows = mysql_num_rows(res); //行数
    int cols = mysql_num_fields(res); //列数
    //获取每列的属性并打印列名
    MYSQL_FIELD* fields = mysql_fetch_fields(res);
    for(int i = 0;i < cols;i++) cout<<fields[i].name<<"\t";
    cout<<endl;
    for(int i = 0;i < rows;i++) {
        //获取一行数据并进行打印
        MYSQL_ROW row = mysql_fetch_row(res);
        for(int j = 0;j < cols;j++) {
            cout<<row[j]<<"\t";
        }
        cout<<endl;
    }
    free(res); //释放内存空间
    //4、关闭数据库
    mysql_close(ms);
    cout<<"数据库关闭成功!"<<endl;
    return 0;
}

使用make命令生成可执行程序,运行后在即可看到数据的查询结果

dcc35e9502aa4c059c51f1a9edc4bf11.png

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5天前
|
关系型数据库 MySQL 数据安全/隐私保护
关于Navicat连接MySQL 报 Authentication plugin ‘caching_sha2_password‘ cannot be loaded
关于Navicat连接MySQL 报 Authentication plugin ‘caching_sha2_password‘ cannot be loaded
|
3天前
|
SQL Oracle 关系型数据库
实时计算 Flink版操作报错合集之连接器换成2.4.2之后,mysql作业一直报错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
16 3
|
5天前
|
SQL 缓存 Java
实时计算 Flink版产品使用合集之flink-connector-mysql-cdc 和 flink-connector-sqlserver-cdc 这两个CDC连接器只能选择其中一个使用吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
27 0
|
6天前
|
关系型数据库 MySQL 数据库
mysql 设置环境变量与未设置环境变量连接数据库的区别
设置与未设置MySQL环境变量在连接数据库时主要区别在于命令输入方式和系统便捷性。设置环境变量后,可直接使用`mysql -u 用户名 -p`命令连接,而无需指定完整路径,提升便利性和灵活性。未设置时,需输入完整路径如`C:\Program Files\MySQL\...`,操作繁琐且易错。为提高效率和减少错误,推荐安装后设置环境变量。[查看视频讲解](https://www.bilibili.com/video/BV1vH4y137HC/)。
91 3
mysql 设置环境变量与未设置环境变量连接数据库的区别
|
6天前
|
关系型数据库 MySQL 数据库
navicat过期了,直接用idea连接mysql
navicat过期了,直接用idea连接mysql
13 0
|
6天前
|
SQL Java 关系型数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
|
6天前
|
存储 算法 关系型数据库
MySQL连接的原理⭐️4种优化连接的手段性能提升240%🚀
MySQL连接的原理⭐️4种优化连接的手段性能提升240%🚀
|
4天前
|
关系型数据库 MySQL API
实时计算 Flink版产品使用合集之可以通过mysql-cdc动态监听MySQL数据库的数据变动吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
80 0
|
7天前
|
关系型数据库 MySQL 数据库
docker MySQL删除数据库时的错误(errno: 39)
docker MySQL删除数据库时的错误(errno: 39)
60 0
|
6天前
|
Java 关系型数据库 MySQL
【MySQL × SpringBoot 突发奇想】全面实现流程 · xlsx文件,Excel表格导入数据库的接口(下)
【MySQL × SpringBoot 突发奇想】全面实现流程 · xlsx文件,Excel表格导入数据库的接口
44 0