• 【MySQL】使用C/C++访问MySQL


    本篇环境是云服务器Centos上的MySQL
    版本;
    在这里插入图片描述

    一. 环境准备

    使用C/C++访问MySQL,首先需要MySQL的开发者库

    这里提供两种方法:

    1. 方法一

    在MySQL的官网下载
    MtySQL Community Downloads

    • 在这里插入图片描述

    红框里的是各种语言的开发者包,本篇博客介绍C语言的接口,也就是C API

    • 在这里插入图片描述

    选择和要访问的MySQL服务器一样环境,版本的开发者包

    • 在这里插入图片描述

    Archives可以看到历史版本
    注意不要下载成Debug版本

    下载完成后,在云服务上使用rz命令将Windows的文件拷贝到云服务上
    在这里插入图片描述
    使用tar xzf 压缩包解压,然后可以再改个名

    里面有很多的库文件,我们主要使用include里的mysql.h

    第一种方法先介绍到这

    2. 方法二

    如果你的MySQL是通过yum源安装的,那么yum在安装MySQL的同时,已经帮我们下好了开发者工具,并且配置好了

    头文件默认放在/usr/include/mysql
    动静态库在/lib64/mysql

    如果没有,使用以下命令安装

    yum install mysql-devel
    
    • 1

    第三方库的使用可以移步【Linux】动静态库

    这里简要说一下使用
    gcc/g++默认搜索的头文件路径是/user/include
    默认搜索的库路径是

    • /usr/local/lib
    • /usr/lib
    • /lib

    编译可执行时需要如下命令

    g++ -o -std=c++11 -I/usr/include/mysql -L/lib64/mysql -lmysqlclient
    
    • 1

    -I选项:指认使用的头文件。如果代码中#include,其实可以不带-I选项,因为g++找得到
    -L选项:指认库路径
    -l:指认链接的库的名字


    简单使用

    makefile

    mytest:test.cc
    	g++ -o $@ $^ -std=c++11 -L/lib64/mysql -lmysqlclient
    .PHONY:clean
    clean:
    	rm -f mytest
    
    • 1
    • 2
    • 3
    • 4
    • 5

    test.cc

    #include
    #include
    
    int main()
    {
        std::cout<<"mysql client version: "<<mysql_get_client_info()<<std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    mysql_get_client_info()是mysql.h中的一个函数,可以获取和次开发包相应对应的mysql客户端版本

    在这里插入图片描述

    运行成功

    二. MySQL接口介绍

    1. 初始化/连接/关闭

    C API的各种接口和变量都可以在官方文档查找
    MySQL官方文档(全)
    下拉找到Conectors&APIs,可以找到C API,选择合适的版本C API 8.0

    左侧的C API Basic Interface里的C API Funciton-reference是各函数C API函数
    C API Basic Data Structures是各种变量,结构体C API结构体

    MySQL本质是网络服务
    C API使用MYSQL结构体管理客户端与服务器的链接等信息

    初始化MYSQL结构体

    MYSQL * mysql_init(MYSQL*mysql)
    
    • 1

    参数可以传nullptr,如果传入一个MYSQL,则会重置此MYSQL,结果都是返回一个新的MYSQL

    链接MySQL

    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
    							)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    MYSQL是C API中一个非常重要的变量,里面内容非常丰富,有port,dbname,charset等链接基本参数,也包含一个st_mysql_methods的结构体变量,里面保存着很多函数指针,这些函数指针将会在数据库连接成功后的各种数据库操作中调用

    如下是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;
    
    • 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
    • host:链接的MySQL服务器的主机IP
    • user:登录的用户
    • passwd:用户密码
    • db:使用的数据库
    • port:MySQL服务器的端口号
    • unix_socket:域间套接字(管道通信),通常为nullptr
    • clientflag:通常为0,其他设置可查看官网

    连接成功会将host,port等信息绑定到MYSQL中
    失败则返回空指针

    可以在MySQL中使用show processlist查看当前连接的用户

    关闭连接

    void mysql_close(MYSQL*mysql);
    
    • 1

    2. 执行操作

    int mysql_query(MYSQL*mysql,const char*sql);
    
    • 1

    mysql:要哪个连接执行
    sql:具体的sql语句

    成功返回0,失败返回非0

    案例:

    准备了一个用户名为’ljh’,密码为123456,登录方式为localhost的用户
    因为本地连接,所以IP使用本地环回127.0.0.1
    端口号默认为3306
    使用test数据库,其中有一个user表
    表结构如下:

    mysql> desc user;
    +-----------+-------------+------+-----+---------+----------------+
    | Field     | Type        | Null | Key | Default | Extra          |
    +-----------+-------------+------+-----+---------+----------------+
    | id        | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name      | varchar(10) | YES  |     | NULL    |                |
    | age       | int(11)     | YES  |     | NULL    |                |
    | telephone | varchar(11) | YES  | UNI | NULL    |                |
    +-----------+-------------+------+-----+---------+----------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    连接代码如下:

    #include
    #include
    #include
    
    const std::string host ="127.0.0.1";
    const std::string user="ljh";
    const std::string passwd="123456";
    const std::string db="test";
    const unsigned int port=3306;
    
    
    int main()
    {
        //初始化
        MYSQL*conn=mysql_init(nullptr);
        if(conn==nullptr)
        {
            //初始化失败
            std::cerr<<"mysql init error"<<std::endl;
            return 1;
        }
    
        //建立连接
        conn=mysql_real_connect(conn,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0);
        if(conn==nullptr)
        {
            std::cerr<<"mysql connect error"<<std::endl;
            return 2;
        }
    
        std::cout<<"mysql connect success"<<std::endl;
    
        //关闭连接
        mysql_close(conn);
    
        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

    insert操作
    在建立连接成功后

    	const std::string sql="insert into user (name,age,telephone) values ('zhangsan',23,'123456')";
        int n=mysql_query(conn,sql.c_str());
        if(n==0)
        {
            std::cout<<sql<<" success "<<std::endl;
        }
        else
        {
            std::cerr<<"sql error"<<std::endl;
            return 3;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    mysql> select * from user;
    Empty set (0.01 sec)
    
    mysql> select * from user;
    +----+----------+------+-----------+
    | id | name     | age  | telephone |
    +----+----------+------+-----------+
    |  1 | zhangsan |   23 | 123456    |
    +----+----------+------+-----------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    delete和update操作同理,只需要更改一下sql就可以了


    编码格式

    但是如果插入的是汉字,则会出现乱码的现象

    const std::string sql="insert into user (name,age,telephone) values ('张三',23,'654321')";
    
    • 1
    mysql> select * from user;
    +----+---------------+------+-----------+
    | id | name          | age  | telephone |
    +----+---------------+------+-----------+
    |  1 | zhangsan      |   23 | 123456    |
    |  4 | å¼ ä¸‰        |   23 | 654321    |
    +----+---------------+------+-----------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    原因是开发者包默认使用的编码格式Latin1,MySQL默认使用utf8

    更改编码格式

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

    csname:指明编码格式

    在建立连接后设置

    mysql_set_character_set(conn,"utf8");
    
    • 1
    mysql> select * from user;
    +----+----------+------+-----------+
    | id | name     | age  | telephone |
    +----+----------+------+-----------+
    |  1 | zhangsan |   23 | 123456    |
    |  5 | 张三     |   23 | 654321    |
    +----+----------+------+-----------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3. 查找操作

    如果执行的sql语句是select,那么还需要调出结果
    select语句通过mysql_query执行成功后,结果会放到MYSQL中,但为了更好的遍历,我们需要将结果拷贝到MYSQL_RES结果集中。

    函数如下:

    MYSQL_RES* mysql_store_result(MYSQL*mysql)
    
    • 1

    在这里插入图片描述

    MYSQL_RES可以理解为一个char**的数组,一行数据其实就是一个char **
    因为约束,所以MySQL的表数据时规整的,可以使用循环遍历

    获取结果集的行数

    uint64_t mysql_num_rows(MYSQL_RES *result)
    
    • 1

    获取结果集的列数

    unsigned int mysql_num_fields(MYSQL_RES *result)
    
    • 1

    行迭代器 MYSQL_ROW
    MYSQL_ROW就是char**

    typedef char **MYSQL_ROW;
    
    • 1

    函数如下

    MYSQL_ROW mysql_fetch_row(MYSQL_RES*res);
    
    • 1

    注意此处返回的是结构体对象,不是指针
    每次调用这个函数后,下次调用都会将MYSQL_ROW定位到下一行数据

    该函数会调用MYSQL变量中的st_mysql_methods中的read_rows函数指针来获取查询结果。同时malloc一片内存空间来存储查询到的数据,所以后续需要free释放这段空间

    void mysql_free_result(MYSQL_RES *result)
    
    • 1

    案例:

    #include
    #include
    #include
    
    const std::string host ="127.0.0.1";
    const std::string user="ljh";
    const std::string passwd="123456";
    const std::string db="test";
    const unsigned int port=3306;
    
    
    int main()
    {
        //初始化
        MYSQL*conn=mysql_init(nullptr);
        if(conn==nullptr)
        {
            //初始化失败
            std::cerr<<"mysql init error"<<std::endl;
            return 1;
        }
    
        //建立连接
        conn=mysql_real_connect(conn,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0);
        if(conn==nullptr)
        {
            std::cerr<<"mysql connect error"<<std::endl;
            return 2;
        }
        std::cout<<"mysql connect success"<<std::endl;
        mysql_set_character_set(conn,"utf8");//设置编码格式
    
        const std::string sql="select * from user";
    	
    	//执行sql语句
        int n=mysql_query(conn,sql.c_str());
        if(n==0)
        {
            std::cout<<sql<<" success "<<std::endl;
        }
        else
        {
            std::cerr<<"sql error"<<std::endl;
            return 3;
        }
        
        //获取结果集
        MYSQL_RES* res=mysql_store_result(conn);
        if(res==nullptr)
        {
            std::cerr<<"store error"<<std::endl;
            return 4;
        }
    
        int row=mysql_num_rows(res);//行数
        int field=mysql_num_fields(res);//列数
    	//遍历
        for(int i=0;i<row;++i)
        {
            MYSQL_ROW rows=mysql_fetch_row(res);
            for(int j=0;j<field;++j)
            {
                std::cout<<rows[j]<<"\t";
            }
            std::cout<<std::endl;
        }
    
    	mysql_free_result(res);
    
        //关闭连接
        mysql_close(conn);
    
        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
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    在这里插入图片描述


    获取列属性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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    可以通过MYSQL_FIELD获取列名,列属性等信息

    案例:

    	MYSQL_FIELD*fields=mysql_fetch_field(res);
        for(int i=0;i<field;++i)
        {
            std::cout<<"列名:"<<fields[i].name<<std::endl;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    结束语

    感谢看到此处
    如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
    在这里插入图片描述

  • 相关阅读:
    Kubernetes中的探针机制
    PT_独立事件
    Spring封装的原生WebSocket使用,带组的实现
    服务器探针-serverstatus
    【Python+Appium】开展自动化测试(十二)通过坐标定位元素
    导购APP、淘客查券机器人与淘客系统:全面对比与选择
    CSS学习|css三种导入方式、基本选择器、层次选择器、结构伪类选择器、属性选择器、字体样式、文本样式
    企业清算有哪些类型?在哪里可以查看相关公告?
    我想告诉你这样做就能做一个简单的个人网站出来:::全流程讲解(阿里云)
    Dart 2.18 正式发布
  • 原文地址:https://blog.csdn.net/m0_72563041/article/details/134353731