关于 C++ 操作 MySQL 数据查询的底层数据结构与函数支持

举报
看,未来 发表于 2021/12/24 21:12:26 2021/12/24
【摘要】 @[toc] 近况这些天,一半的时间都花在练车了,导致毕设进度就慢下来了。而且最近完美主义越来越严重,就加了个调优的小版本。本来今天应该进入第二个阶段了(主redis),结果现在还在对第一个版本进行调优。所以目前还是主mysql。写了这么多天的mysql代码,不敢说很熟练,但是有件事情一定要做一下,那就是把“本质”拿出来晾晒晾晒,不能天天稀里糊涂的调API吧(确实稀里糊涂,因为没有看过API...

请添加图片描述

@[toc]

近况

这些天,一半的时间都花在练车了,导致毕设进度就慢下来了。而且最近完美主义越来越严重,就加了个调优的小版本。本来今天应该进入第二个阶段了(主redis),结果现在还在对第一个版本进行调优。所以目前还是主mysql。

写了这么多天的mysql代码,不敢说很熟练,但是有件事情一定要做一下,那就是把“本质”拿出来晾晒晾晒,不能天天稀里糊涂的调API吧(确实稀里糊涂,因为没有看过API的源码)


示例函数

先来段函数示例吧,放码过去:
MySQL是我封装的一个类,函数名没改动,原滋原味。

MySQL mysql;
if (mysql.connect())
{
    MYSQL_RES *res = mysql.query(sql1);		//first blood
    if (res != nullptr)
    {
            ···
        int num_fields = mysql_num_fields(res);	//注
					 
					 //double kill
        MYSQL_ROW row = mysql_fetch_row(res); //mysql_fetch_row()毎执行一次,都从资源也就是结果集中依次取一条数据,
                                                  //以数组的形式返回出来,当前一次取得最后一条数据,返回空结果。
                                                  //返回数组都是一维索引数组,每一个下标与数据库的排序一一对应
        while (row != nullptr)
        {
            for (int i = 0; i < num_fields; i++)
            {
                    ···
            }
                
            row = mysql_fetch_row(res);	//注
        }
        mysql_free_result(res);	//注
    }
}
// 查询操作
MYSQL_RES *MySQL::query(string sql)
{
    if (mysql_query(_conn, sql.c_str()))
    {
        LOG_INFO << __FILE__ << ":" << __LINE__ << ":" << sql << "查询失败!";
        cout << mysql_error(_conn) << endl;
        return nullptr;
    }

    return mysql_use_result(_conn);
}

这里面涉及了一些,在mysql查询中常用的数据结构和函数,如果对其构成不清楚明了的话,用起来那可不就是稀里糊涂嘛!!!


数据结构

MYSQL_RES

这是一个用于存放mysql结果集的数据结构。这么讲没意思,直接看构成:

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;

这里面就有我们很关心的:行数、列数、数据。


MYSQL_DATA

typedef struct st_mysql_data {
    my_ulonglong rows;
    unsigned int fields;
    MYSQL_ROWS *data;
    MEM_ROOT alloc;
} MYSQL_DATA; // 数据集的结构 

MYSQL_ROWS

typedef struct st_mysql_rows {
    struct st_mysql_rows *next; /* list of rows */
    MYSQL_ROW data;
} MYSQL_ROWS;        //mysql的数据的链表节点。

MYSQL_ROW

typedef char** MYSQL_ROW; /* 返回的每一行的值,全部用字符串来表示*/ 

MYSQL_FIELD

typedef struct st_mysql_field {
    char *name;  /* Name of column */
    char *table;                               /* Table of column if column was a field */
    char *def;                                 /* Default value (set by mysql_list_fields) */
    enum enum_field_types type;                /* Type of field. Se mysql_com.h for types */
    unsigned int length;                       /* Width of column */
    unsigned int max_length;                   /* Max width of selected set */
    unsigned int flags;                        /* Div flags */
    unsigned int decimals;                     /* Number of decimals in field */
} MYSQL_FIELD;  //列信息的结构 

相关API

mysql_store_result

MYSQL_RES *mysql_store_result(MYSQL *mysql); 

mysql_store_result()将查询的全部结果读取到客户端,分配1个MYSQL_RES结构。

如果查询未返回结果集,mysql_store_result()将返回NULL指针。

如果读取结果集失败,mysql_store_result()也会返回NULL指针。通过检查mysql_error()是否返回非空字符串,mysql_errno()是否返回非0值,或mysql_field_count()是否返回0,可以检查是否出现了错误。


mysql_use_result

MYSQL_RES *mysql_use_result(MYSQL *mysql);
//如果出现错误,返回NULL。

mysql_use_result()将结果保存在服务器,它必须通过对mysql_fetch_row()的调用,对每一行分别进行检索。与mysql_store_result()相比,速度更快而且使用的内存也更少。

另一方面,这会绑定服务器,并阻止其他线程更新任何表(确实,我试过,在free之前无法执行任何命令)。
如果你正在客户端一侧为各行进行大量的处理操作,就不应使用mysql_use_result()。

一旦完成了对结果集的操作,必须调用mysql_free_result()。


mysql_fetch_row

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

检索结果集的下一行,结束检索则返回null。

结果集的列数目由mysql_num_fields(result)给出。如果行中保存了调用mysql_fetch_row()返回的值,将按照row[0]row[mysql_num_fields(result)-1],访问这些值的指针。行中的NULL值由NULL指针指明。

可以通过调用mysql_fetch_lengths()来获得行中字段值的长度。对于空字段以及包含NULL的字段,长度为0。
通过检查字段值的指针,也能够区分它们。


mysql_fetch_field

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);

返回采用MYSQL_FIELD结构的结果集的列。重复调用该函数,以检索关于结果集中所有列的信息。未剩余字段时,mysql_fetch_field()返回NULL。

每次执行新的SELECT查询时,将复位mysql_fetch_field(),以返回关于第1个字段的信息。调用mysql_field_seek()也会影响mysql_fetch_field()返回的字段。

如果调用了mysql_fetch_field()以请求BLOB字段的长度,MySQL将返回默认的Blob长度(8KB)。之所以选择8KB是因为MySQL不知道BLOB的最大长度。应在日后使其成为可配置的。一旦检索了结果集,field->max_length将包含特定查询中该列的最大值的长度。


mysql_free_result

void mysql_free_result(MYSQL_RES *result);

释放由mysql_store_result()、mysql_use_result()、mysql_list_dbs()等为结果集分配的内存。完成对结果集的操作后,必须调用mysql_free_result()释放结果集使用的内存。

释放完成后,不要尝试访问结果集。


我讲明白了吗?

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。