关于C语言连接数据所涉及到的各种数据结构的介绍以及相关函数的使用其实在 MySQL C API 官方文档中已经给出了,我们可以通过它来快速了解并上手 MySQL C API。
要使用 MySQL C语言库,需要先使用 mysql_init 函数完成对 MYSQL 结构体指针的初始化工作。
MYSQL *mysql_init(MYSQL *mysql)
注意:mysql_init 函数的参数以及返回值都是 MYSQL 指针类型,对于 MYSQL,大家把它类比到C语言中的文件指针来理解即可。MYSQL 和C语言文件 FILE 一样,本质上都是一个结构体。
MYSQL *mfp = mysql_init(nullptr); if(mfp == nullptr) { cerr << "mysql init error" << endl; return 1; } cout << "mysql init success" << endl;
注意:这里用C语言的 NULL 还是C++的 nullptr 都可以,因为它们在数值上都是0;区别在于在定义时 NULL 是一个整数,而 nullptr 则是被强转为了 void* 类型。
初始化完毕后,我们需要使用 mysql_real_connect 函数来连接数据库。
MYSQL * mysql_real_connect(MYSQL *mysql, // MYSQL结构体指针对象 const char *host, // mysqld服务进程所在的主机 const char *user, // 登录MySQL的用户 const char *passwd, // 用户密码 const char *db, // 要访问的数据库 unsigned int port, // mysqld服务进程的端口号 const char *unix_socket, // 默认设为NULL即可 unsigned long client_flag) // 默认设为0即可
#define HOST "127.0.0.1" //MySQL不允许远程访问 出于安全考虑 所以只可以使用本地网络 127.0.0.1 #define USER "li_zheng_yang" #define PASS "Gaopengyan99999." #define DBNAME "Five_in_a_row" #define PORT 3306 //这是系统API接口默认的 if( mysql_real_connect(mysql,HOST,USER,PASS,DBNAME,PORT,NULL,0)==nullptr )//第一个参数叫句柄 { cout << "connect failed" << endl; cout << mysql_error(mysql);//放入句柄 查看连接失败原因 mysql_close(mysql); return -1; }
需要注意的是,我们之前在创建数据库时默认使用的字符集是 utf8,而C语言连接数据时默认的字符集是 latin1 的(拉丁),这就会导致我们在向表中插入中文数据时,由于字符集不匹配,最终数据库中存储的数据显式出来是乱码。
所以,我们需要使用 mysql_set_character_set 函数设置连接字符集为 utf8。
int mysql_set_character_set(MYSQL *mysql, const char *csname)
int n = mysql_set_character_set(mfp, "utf8"); if(n != 0) { cout << "warning: character set fail" << endl; }
在成功连接到数据库之后,我们就可以通过 mysql_query 函数来下发 mysql 指令了。
int mysql_query(MYSQL *mysql, const char *stmt_str)
//增删改查 int mysql_query(MYSQL *mysql, const char *stmt_str) 这里的第二个参数前面必须加上 const const char* sql="insert stu values(null,'lzy',21,100,100,100);"; //const char* sql="update stu set ch=ch-1 where sn=1;"; //const char* sql="delete from stu where sn=1;"; int ret=mysql_query(mysql,sql);
需要注意的是,我们在使用 mysql client 时,一条 sql 语句需要以分号结尾;但是在C语言中,sql 语句可以不用带分号,当然带上也没事。
检验是否插入成功:
select* from stu;
检验是否修改成功:
我们上面是对数据库执行增删改操作,它们相对来说比较简单,因为我们只需要将指令下发给数据库即可,后面的事情我们不必关心。但==如果我们执行的是查询操作,则需要通过 mysql_store_result 函数来获取查询结果==。
MYSQL_RES *mysql_store_result(MYSQL *mysql)
实际上,mysql_store_result 函数会调用 MYSQL 结构体变量中的 st_mysql_methods 字段中的 read_rows 函数指针来获取查询的结果;然后将查询结果保存到 MYSQL_RES 结构体中并返回结构体指针。这样,当执行完 mysql_store_result 以后,其实数据都已经在MYSQL_RES 变量中了,我们直接从中获取即可。
需要注意的是,MYSQL_RES 是通过 malloc/new 空间的方式来保存查询结果的,所以当我们使用完毕之后,一定要记得释放 MYSQL_RES 对象,否则就会造成内存泄漏。同时,MYSQL_RES 结构体中存在查询结果的列数、列信息、行数、行内容等属性,我们需要使用对应的函数来获取这些信息。
行
unsigned int mysql_num_rows(MYSQL_RES *result)
列
unsigned int mysql_num_fields(MYSQL_RES *result)
for(int i=0;i//MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) MYSQL_ROW row=mysql_fetch_row(res); for(int i=0;i cout << row[i] << "\t"; }cout << endl; }
当然,我们也可以通过调用 mysql_fetch_fields 函数一次获取到所有列的属性信息,然后分别打印。
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
my_ulonglong mysql_num_rows(MYSQL_RES *result)
由于 MYSQL_RES 保存查询结果的空间是通过 malloc/new 得到的,所以当我们使用完毕后需要释放掉 MYSQL_RES 对象,防止内存泄露。
void mysql_free_result(MYSQL_RES *result)
mysql_free_result(res);
最后,当我们使用完 MySQL 后,需要关闭 MySQL 之前建立的连接。
void mysql_close(MYSQL *sock);
mysql_close(mfp);
使用 MySQL C API 连接数据库进行简单操作的步骤如下:
#include#include using namespace std; #define HOST "127.0.0.1" //MySQL不允许远程访问 出于安全考虑 所以只可以使用本地网络 127.0.0.1 #define USER "root" #define PASS "Gaopengyan99999." #define DBNAME "Five_in_a_row" #define PORT 3306 //这是系统API接口默认的 int main() { 1.初始化MySQL句柄 MYSQL* mysql = mysql_init(nullptr);//MYSQL *mysql_init(MYSQL *mysql) 传空 那么就是堆上申请空间 //MYSQL 和C语言文件 FILE 一样,本质上都是一个结构体 所以mysql就相当于是结构体创建的节点 //类似于 ListNode* node if(mysql==nullptr) { cout << "create fail" << endl; return -1; } /2.连接服务器 /*MYSQL * mysql_real_connect(MYSQL *mysql, // MYSQL结构体指针对象 const char *host, // mysqld服务进程所在的主机 const char *user, // 登录MySQL的用户 const char *passwd, // 用户密码 const char *db, // 要访问的数据库 unsigned int port, // mysqld服务进程的端口号 const char *unix_socket, // 默认设为NULL即可 unsigned long client_flag) // 默认设为0即可*/ if( mysql_real_connect(mysql,HOST,USER,PASS,DBNAME,PORT,NULL,0)==nullptr )//第一个参数叫句柄 { cout << "connect failed" << endl; cout << mysql_error(mysql);//放入句柄 查看连接失败原因 mysql_close(mysql); return -1; } /3.设置客户端字符集/// if( mysql_set_character_set(mysql,"utf8") != 0 ) //文档规定 为0则为成功 非0则失败了 { cout << "set character failed" << endl; cout << mysql_error(mysql);//放入句柄 查看连接失败原因 mysql_close(mysql); return -1; } /4.选择要操作的数据库/ //这一步不需要进行了 我们在连接服务器的时候实则已经默认选择过了 //mysql_select_db(mysql,DBNAME); //5.执行sql语句// //增删改查 int mysql_query(MYSQL *mysql, const char *stmt_str) 这里的第二个参数前面必须加上 const //const char* sql="insert stu values(null,'lzy',21,100,100,100);"; //const char* sql="update stu set ch=ch-1 where sn=1;"; //const char* sql="delete from stu where sn=1;"; const char* sql="select * from stu;"; int ret=mysql_query(mysql,sql); if( ret!=0 )//查询和增删改不一样 得保存数据到本地 { cout << "find failed" << endl; cout << mysql_error(mysql);//放入句柄 查看连接失败原因 mysql_close(mysql); return -1; } ///6.select保存结构到本地/ MYSQL_RES *res=mysql_store_result(mysql); if( res == nullptr) { mysql_close(mysql); return -1; } //7.获取行数与列数 //unsigned int mysql_num_fields(MYSQL_RES *result) //unsigned int mysql_num_rows(MYSQL_RES *result) int num_row=mysql_num_rows(res);//res是上面用mysql_store_result获取出来保存进去的结果 int num_col=mysql_num_fields(res); //8.遍历读取数据 for(int i=0;i //MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) MYSQL_ROW row=mysql_fetch_row(res); for(int i=0;i cout << row[i] << "\t"; }cout << endl; } //9.释放结果集/// mysql_free_result(res); /10.关闭连接/ mysql_close(mysql); }