【MySQL】C/C++引入MySQL客户端
- 安装mysqlclient库
- mysql接口介绍
- 初始化mysql_init
- 链接数据库mysql_real_connect
- 下发mysql命令mysql_query
- 获取出错信息mysql_error
- 获取执行结果mysql_store_result
- 获取结果行数mysql_num_rows
- 获取结果列数mysql_num_fields
- 判断结果列数mysql_field_count
- mysql_num_fields 与 mysql_field_count的区别
- 获取列名mysql_fetch_fields
- 获取结果内容mysql_fetch_row
- 获取列当前列的长度mysql_fetch_lengths
- 释放结果集mysql_freer_result
- 关闭mysql链接mysql_close
- 整体测试代码
- 图形化界面连接
- 下载workbench
- Ubuntu提供mysql权限
- workbench图形化连接
安装mysqlclient库
- 安装mysql
Ubuntu安装MySQL8.0 - 安装连接库
在Ubuntu上使用C/C++连接MySQL 8.0,你需要使用MySQL官方提供的连接器库,即libmysqlclient。
sudo apt-install libmysqlclient-dev
执行时需要连接这个库
gcc -o xxx yyy -lmysqlclient
mysql接口介绍
相关具体函数可到mysql官网中去查询链接: 直接点击查看所有8.0版本函数
- 找到官网

- 找到CAPI

- 查看所有函数

初始化mysql_init
要使用库,必须先进行初始化!
MYSQL *mysql_init(MYSQL *mysql)
分配或初始化适用于 mysql_real_connect() 的 MYSQL 对象。如果 mysql 为 NULL 指针,则该函数分配、初始化并返回一个新对象。否则,将初始化该对象并返回该对象的地址。如果 mysql_init() 分配了一个新对象,则在调用 mysql_close() 关闭连接时将释放该对象。
在非多线程环境中,mysql_init() 会根据需要自动调用 mysql_library_init()。但是,mysql_library_init() 在多线程环境中不是线程安全的,因此 mysql_init() 也不是。在调用 mysql_init() 之前,要么在生成任何线程之前调用 mysql_library_init(),要么使用互斥锁来保护 mysql_library_init() 调用。这应该在任何其他客户端库调用之前完成。
所以一般mysql_int()的这个里面的参数都是null;
已初始化的 MYSQL* 处理程序。如果内存不足以分配新对象,则返回 NULL。
链接数据库mysql_real_connect
初始化完毕之后,必须先链接数据库,在进行后续操作。(mysql网络部分是基于TCP/IP的)
MYSQL *mysql_real_connect(MYSQL *mysql,const char*host,const char*user,const char*passwd,const char*db,unsignedintport,const char*unix_socket,unsignedlong client_flag)mysql_set_character_set(myfd,"utf8");
参数解析:
- 第一个参数 MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
- host:连接的主机名/ip
- user:连接的用户名
- passwd:连接数据库的密码
- db:连接数据库的名称
- port:连接数据库的端口号
- unix_socket:连接数据库的连接方式(一般直接设置为NULL即可)
- client_flag:这个也是一般直接设置为0即可
如果连接成功,则返回 MYSQL* 连接处理程序;如果连接失败,则返回 NULL。对于成功的连接,返回值与第一个参数的值相同。
intmain(){ MYSQL*my =mysql_init(nullptr);if(my ==NULL){ std::cerr <<"mysql init error..."<<std::endl;return1;}if(mysql_real_connect(my,host.c_str(),user.c_str(),password.c_str(),db.c_str(),port,NULL,0)==nullptr){ std::cerr <<"mysql connect error..."<<std::endl;return2;}std::cout <<"mysql connect success..."<<std::endl;sleep(10);mysql_close(my);return0;}

从上面的结果我们也可以看出是连接成功的了。
下发mysql命令mysql_query
intmysql_query(MYSQL *mysql,constchar*stmt_str)
执行以空字符结尾的字符串 stmt_str 指向的 SQL 语句。通常,该字符串必须由一条 SQL 语句组成,且不带终止分号 ( ; ) 或 \g。如果已启用多语句执行,则该字符串可以包含多条以分号分隔的语句。
mysql_query() 不能用于包含二进制数据的语句;您必须使用 mysql_real_query()。(二进制数据可能包含 \0 字符,mysql_query() 将其解释为语句字符串的结尾。)
第一个参数时mysql_init的返回值,第二个参数时要执行的SQL语句
零表示成功。非零值表示发生错误。
创建一张新表
std::string sql ="create table test(id int primary key, name varchar(20))";if(mysql_query(my,sql.c_str())!=0){ std::cerr <<"mysql query error..."<<std::endl;std::cout <<mysql_error(my)<<std::endl;return3;}std::cout <<"mysql query success..."<<std::endl;
Databasechangedmysql>showtables;+|Tables_in_conn |+|test |+1rowinset(0.00sec)mysql>desctest;+|Field |Type|Null|Key|Default|Extra |+|id |int|NO|PRI |NULL|||name |varchar(20)|YES ||NULL||+2rowsinset(0.01sec)
获取出错信息mysql_error
- 函数原型:
constcharmysql_error(MYSQL *mysql);
对于 mysql 指定的连接,mysql_error() 返回一个以空字符结尾的字符串,其中包含最近调用的失败的 API 函数的错误消息。如果函数未失败,mysql_error() 的返回值可能是前一个错误或一个空字符串(表示没有错误)。
经验法则是,所有必须向服务器询问信息的函数如果成功则重置 mysql_error()。
- 参数解析
参数就是mysql_init的返回值
- 返回值
描述错误的以空字符结尾的字符串。如果没有发生错误,则为空字符串。
- 案例
我们再次执行mysql_query的命令,创建一张表

获取执行结果mysql_store_result
- 函数原型:
MYSQL_RES *mysql_store_result(MYSQL *mysql)
该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows 函数指针来获取查询的结果。同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。

- 参数解析
参数就是mysql_init的返回值
typedefstructMYSQL_RES{ uint64_trow_count;MYSQL_FIELD *fields;structMYSQL_DATA*data;MYSQL_ROWS *data_cursor;unsignedlong*lengths;MYSQL *handle;conststructMYSQL_METHODS*methods;MYSQL_ROW row;MYSQL_ROW current_row;structMEM_ROOT*field_alloc;unsignedintfield_count,current_field;bool eof;bool unbuffered_fetch_cancelled;enumenum_resultset_metadatametadata;void*extension;}MYSQL_RES;
- 返回值
指向包含结果的 MYSQL_RES 结果结构的指针。如果语句未返回结果集或发生错误,则为 NULL。要确定是否发生错误,请检查 mysql_error() 是否返回非空字符串、mysql_errno() 是否返回非零,或 mysql_field_count() 是否返回零。
- 案例
mysql>select*fromtest;+|id |name |+|1|张三 ||2|李四 ||3|王五 |+3rowsinset(0.00sec)
uint64_trows =mysql_num_rows(res);unsignedintcols =mysql_num_fields(res);std::cout <<"行:"<<rows <<",列"<<cols <<std::endl;

获取结果行数mysql_num_rows
- 函数原型
uint64_tmysql_num_rows(MYSQL_RES *result)
- 参数
参数是mysq_stroe_result的返回值。
- 返回值
返回结果集中的行数
获取结果列数mysql_num_fields
- 函数原型:
unsignedintmysql_num_fields(MYSQL_RES *result)
您可以从指向结果集或连接处理程序的指针获取列数。如果 mysql_store_result() 或 mysql_use_result() 返回 NULL(因此您没有结果集指针),则可以使用连接处理程序。在这种情况下,您可以调用 mysql_field_count() 来确定 mysql_store_result() 是否应该产生非空结果。这使客户端程序能够采取适当的操作,而无需知道查询是否为 SELECT(或类似 SELECT)语句。此处显示的示例说明了如何完成此操作。
- 参数解析
参数就是mysql_store_result的返回值
- 返回值
返回结果集中的列数,表示结果集中列数的无符号整数。
判断结果列数mysql_field_count
- 函数原型
unsignedintmysql_field_count(MYSQL *mysql)
此函数的正常使用是当 mysql_store_result() 返回 NULL(因此您没有结果集指针)时。在这种情况下,您可以调用 mysql_field_count() 来确定 mysql_store_result() 是否应该产生非空结果。这使客户端程序能够采取适当的操作,而无需知道查询是否是 SELECT(或类似 SELECT)语句。此处显示的示例说明了如何执行此操作
- 参数
参数就是mysql_init的返回值
- 返回值
返回连接上最近查询的列数。
mysql_num_fields 与 mysql_field_count的区别
- 参数区别
首先就是mysql_num_fields的参数是mysql_store_result的返回值,而mysql_field_count的参数则是mysql_init的返回值。
- 用途区别
虽然这两个函数返回的都是字段列的个数。但是他们的作用以及查询的条件也是不一样的。mysql_field_count函数是返回作用在连接上的最近查询的列数,它的主要用途是在mysql_store_result()返回NULL(因而没有结果集指针)时,通过调用mysql_field_count()来判断mysql_store_result()是否应生成非空结果。而mysql_num_fields是根据mysql_store_result的返回值来查询列数的。因为像insert,update,select作用在mysql_store_result函数时是没有返回值的,所以这个时候mysql_store_result返回的就是NULL,而mysql_num_fields函数内部肯定是要对mysql_store_result的返回值做解引用的,这个时候对NULL做解引用显然会出现错误,所以需要加以判断。
- 综上所述
其实mysql_field_count更像时起到了一个判断的作用,而mysql_num_fields才像是一样获取列数的函数。两者在使用场景和返回值上有所区别,前者更侧重于查询的结果判断,而后者则提供具体的字段信息
- mysql官网上的示例
if(mysql_query(&mysql,query_string)){ }else{ result =mysql_store_result(&mysql);if(result){ num_fields =mysql_num_fields(result);}else{ if(mysql_field_count(&mysql)==0){ num_rows =mysql_affected_rows(&mysql);}else{ fprintf(stderr,"Error: %s\n",mysql_error(&mysql));}}}
- 注意事项
select0select0select0select0
从上面我们也可以发现,就算我们查找的id=0的行数=0,也就是没有这条记录,但是mysql_field_count和mysql_num_fields显示的都不是0(假设列字段为2)都显示为2。所以我们就可以得出一结论。在执行mysql_store_result时有两个结果:第一种结构就是执行delete,update,insert这样的语句时,mysql_store_result返回的是NULL,此时可以用mysql_field_count来进行判断。第二就是执行select,show这样的语句时一定是有返回值的,但是返回的记录也就是行可以是为0的,也可以不为0,这就有点像一张表可以没有内容,但是一定会有表头。
获取列名mysql_fetch_fields
- 函数原型:
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)
返回结果集的所有 MYSQL_FIELD 结构的数组。每个结构为结果集的一列提供字段定义。也就是返回列属性。
- 参数解析
参数就是mysq_store_result的返回值
typedefstructMYSQL_FIELD{ char*name;char*org_name;char*table;char*org_table;char*db;char*catalog;char*def;unsignedlonglength;unsignedlongmax_length;unsignedintname_length;unsignedintorg_name_length;unsignedinttable_length;unsignedintorg_table_length;unsignedintdb_length;unsignedintcatalog_length;unsignedintdef_length;unsignedintflags;unsignedintdecimals;unsignedintcharsetnr;enumenum_field_typestype;void*extension;}MYSQL_FIELD;
- 返回值
结果集所有列的 MYSQL_FIELD 结构数组。如果结果集没有元数据,则为 NULL。每个结构为结果集的一列提供字段定义。
- 案例
MYSQL_FIELD *fields =mysql_fetch_fields(res);for(inti =0;i <cols;i++){ std::cout <<fields[i].name <<" ";}std::cout <<std::endl;

获取结果内容mysql_fetch_row
- 函数原型:
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char **.就当成一个二维数组来用吧。
typedefchar**MYSQL_ROW;
- 参数解析
参数就是mysql_store_result的返回值
- 返回值
描述错误的以空字符结尾的字符串。如果没有发生错误,则为空字符串。
- 案例
其实这个函数我们可以看作是C++的迭代器,他会自动进行往后遍历
MYSQL_ROW line;for(inti =0;i <rows;i++){ line =mysql_fetch_row(res);for(intj =0;j <cols;j++){ std::cout <<line[j]<<" ";}std::cout <<std::endl;}

获取列当前列的长度mysql_fetch_lengths
- 函数原型
unsignedlong*mysql_fetch_lengths(MYSQL_RES *result)
返回结果集中当前行的列的长度。如果您计划复制字段值,此长度信息对于优化也很有用,因为您可以避免调用 strlen()。此外,如果结果集包含二进制数据,则必须使用此函数来确定数据的大小,因为 strlen() 对于任何包含空字符的字段都会返回不正确的结果。
mysql_fetch_lengths() 仅对结果集的当前行有效。如果在调用 mysql_fetch_row() 之前或在检索结果中的所有行之后调用它,它将返回 NULL。
- 参数
参数就是mysql_store_result的返回值
- 返回值
表示每列大小的无符号长整数数组(不包括任何终止空字节)。如果发生错误,则返回 NULL。
- 案例
unsignedlong*lengths =mysql_fetch_lengths(res);if(rows){ for(inti =0;i <cols;i++){ printf("Column %u is %lu bytes in length.\n",i,lengths[i]);}std::cout <<std::endl;}

释放结果集mysql_freer_result
voidmysql_free_result(MYSQL_RES *result)
mysql_free_result() 释放由 mysql_store_result()、mysql_use_result()、mysql_list_dbs() 等为结果集分配的内存。处理完结果集后,必须通过调用 mysql_free_result() 释放其使用的内存。
所以一般再时使用完结果集后要释放它,防止内存泄漏。
关闭mysql链接mysql_close
- 函数原型:
voidmysql_close(MYSQL *mysql)
关闭先前打开的连接。如果处理程序是由 mysql_init() 或 mysql_connect() 自动分配的,mysql_close() 还会释放由 mysql 指向的连接处理程序。关闭后请勿使用该处理程序。
- 参数解析
参数就是mysql_init的返回值
整体测试代码
#include#include#include#includeconststd::string host ="localhost";conststd::string user ="chuyang";conststd::string password ="123456";conststd::string db ="conn";constunsignedintport =3306;intmain(){ MYSQL *my =mysql_init(nullptr);if(my ==NULL){ std::cerr <<"mysql init error..."<<std::endl;return1;}if(mysql_real_connect(my,host.c_str(),user.c_str(),password.c_str(),db.c_str(),port,NULL,0)==nullptr){ std::cerr <<"mysql connect error..."<<std::endl;return2;}mysql_set_character_set(my,"utf8");std::cout <<"mysql connect success..."<<std::endl;std::string sql ="create table if not exists test(id int primary key, name varchar(20))";if(mysql_query(my,sql.c_str())!=0){ std::cerr <<"mysql query error..."<<std::endl;std::cout <<mysql_error(my)<<std::endl;return3;}std::cout <<"mysql query success..."<<std::endl;sql ="select * from test";if(mysql_query(my,sql.c_str())!=0){ std::cerr <<"mysql query error..."<<std::endl;std::cout <<mysql_error(my)<<std::endl;return3;}MYSQL_RES *res =mysql_store_result(my);if(nullptr ==res){ std::cerr <<"mysql stroe result error..."<<std::endl;std::cout <<mysql_error(my)<<std::endl;return4;}std::cerr <<"mysql stroe result success..."<<std::endl;uint64_trows =mysql_num_rows(res);unsignedintcols =mysql_num_fields(res);std::cout <<"行:"<<rows <<",列"<<cols <<std::endl;MYSQL_FIELD *fields =mysql_fetch_fields(res);for(inti =0;i <cols;i++){ std::cout <<fields[i].name <<" ";}std::cout <<std::endl;MYSQL_ROW line;for(inti =0;i <rows;i++){ line =mysql_fetch_row(res);for(intj =0;j <cols;j++){ std::cout <<line[j]<<" ";}std::cout <<std::endl;}unsignedlong*lengths =mysql_fetch_lengths(res);if(rows){ for(inti =0;i <cols;i++){ printf("Column %u is %lu bytes in length.\n",i,lengths[i]);}std::cout <<std::endl;}mysql_free_result(res);mysql_close(my);return0;}
图形化界面连接
这里用的是workbanch进行的连接
下载workbench
- 进入MySQL官网

- 点击社区版

- 下载workbench

Ubuntu提供mysql权限
因为Ubuntu下我们的mysql不推荐给root账号使用登录,而是创建普通用户让其登陆。
mysql>createuser'chuyang'@'%'identified by'密码';mysql>grantallonconn.*to'chuyang'@'%';mysql>selectUser,Host fromuser;+|User|Host |+|chuyang |%||mysql.infoschema |localhost ||mysql.session|localhost ||mysql.sys |localhost ||root |localhost |+5rowsinset(0.00sec)
workbench图形化连接


