MySQL API 使用详解 | 爱编程的大丙 (subingwen.cn)
1 2 3 4 5 6 #include <mysql.h> 以上api对应的MySQL动态库 Windows: libmysql.dll Linux: libmysqlclient.so
MySQL提供给C的库中所有的函数围绕一个结构体MYSQL,也就是说程序与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 typedef struct st_mysql { NET net; gptr connector_fd; 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; my_ulonglong extra_info; unsigned long thread_id; 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; my_bool reconnect; char scramble_buff[SCRAMBLE_LENGTH+1 ]; my_bool unused1; void *unused2,*unused3,*unused4; LIST *stmts; const struct st_mysql_methods *methods ; void *thd; my_bool *unbuffered_fetch_owner; char *info_buffer; void *extension; } MYSQL;
主要字段说明
NET net : 处理与服务器之间的网络通信。包含套接字描述符、输入/输出缓冲区、超时设置等信息。
char *host : 连接的服务器主机名或IP地址。
char *user : 数据库用户名。
char *passwd : 用户密码。
char *unix_socket : Unix域套接字的路径(如果使用)。
char *db : 当前使用的数据库名称。
struct charset_info_st *charset : 指向当前使用字符集的信息结构。
my_ulonglong affected_rows : 最近一次执行的SQL语句影响的行数(适用于 INSERT、UPDATE、DELETE 操作)。
my_ulonglong insert_id : 最近一次插入操作产生的自增ID。
unsigned long thread_id : 当前连接的线程ID。
struct st_mysql_options options : 连接选项的相关结构体,保存了各种连接参数和配置。
enum mysql_status status : 当前连接的状态,如连接中、已关闭等。
my_bool reconnect : 表示是否在连接丢失时自动重连。
LIST *stmts : 保存预处理的SQL语句。
const struct st_mysql_methods *methods : 指向操作MySQL对象的函数指针表,提供了多态性的支持。
void *thd : 线程数据指针,用于存储每个线程的上下文信息。
void *extension : 供未来扩展使用的字段。
备注
NET 结构体用于管理网络通信,如读取和写入数据包。
MYSQL_FIELD 结构体用于保存列的信息,如列名、类型等。
该结构体使用了许多 typedef 类型和复杂的数据结构,如 MEM_ROOT、LIST、my_ulonglong 等,这些都是MySQL内部定义的类型。
methods 字段使用了指向函数的指针表,这使得 MYSQL 结构体可以通过方法表执行不同的操作,实现了一定的面向对象的设计。
最开始调用的函数**MYSQL* mysql_init(MYSQL* mysql)**,就是为创建一个MYSQL对象在堆区开辟一块空间,并返回这块空间的地址。
1 2 3 4 MYSQL* mysql_init (MYSQL* mysql) ;
然后调用**mysql_real_connect()**函数,让上面创建的MYSQL对象与数据库连接。如果连接成功的话,函数返回的是刚刚传入的想要与数据库建立连接的MYSQL对象的地址,表示我们传入的MYSQL对象与数据库连接成功了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 client_flag ) ;
成功建立连接后,我们就可以通过这个MYSQL对象用**mysql_query()**函数向mysql服务器发送一些sql语句让服务器去执行,函数执行完后,sql语句的执行结果集仍然存储在远端服务器中等待我们收取。
1 2 3 4 5 6 7 8 int mysql_query (MYSQL* mysql, const char * query) ;参数: - mysql: 成功与某mysql服务器建立连接的MYSQL对象的地址 - query: 一个可以执行的sql语句, 语句结尾不需要加 ';' 返回值: - 如果查询成功,返回0 。 - 如果出现错误,返回非0 值。
服务器成功执行sql语句后,执行的结果集需要我们调用**mysql_store_result()**函数将结果集从远端接收到客户端内存中。这个函数会创建一个MYSQL_RES对象来存储收到的结果集,大概可以想成一个表格吧。
1 2 3 4 5 MYSQL_RES* mysql_store_result (MYSQL* mysql) ;
下面的函数就是用来处理MYSQL_RES对象的函数
mysql_num_fields()
获取字段的个数
1 2 3 4 unsigned int mysql_num_fields (MYSQL_RES *result)
mysql_fetch_fields()
获取所有字段的名称
1 2 3 4 5 MYSQL_FIELD* mysql_fetch_fields (MYSQL_RES* result) ;
FIELD表示一个字段,用**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 24 25 typedef struct st_mysql_field { char *name; char *org_name; char *table; char *org_table; char *db; char *catalog; char *def; unsigned long length; unsigned long max_length; 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; unsigned int decimals; unsigned int charsetnr; enum enum_field_types type ; void *extension; } MYSQL_FIELD;
打印结果集的所有字段
1 2 3 4 5 6 7 8 MYSQL_FIELD* fields = mysql_fetch_fields(res); int num = mysql_num_fields(res);for (int i = 0 ; i < num; i++) { printf ("当前列的名字: %s\n" , fields[i].name); }
mysql_fetch_row()
获取下一条记录
函数在调用时,最初指向的行是结果集的第一行之前。也就是说,当你第一次调用 mysql_fetch_row() 时,它会移动到结果集的第一行并返回该行的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 typedef char ** MYSQL_ROW;MYSQL_ROW mysql_fetch_row (MYSQL_RES* result) ; 参数: - result: 通过查询得到的结果集 返回值: - 成功: 得到了当前记录字符串数组,每个字符串是对应字段的值 - 失败: NULL , 说明数据已经读完了
mysql_fetch_lengths()
获取当前指向的记录所有字段值的长度
1 2 3 4 5 6 7 8 9 10 unsigned long *mysql_fetch_lengths (MYSQL_RES *result) ;参数: - result: 通过查询得到的结果集 返回值: - 无符号长整数的数组表示各列的大小。如果出现错误,返回NULL 。
对记录的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 MYSQL_ROW row; unsigned long * lengths;unsigned int num_fields;row = mysql_fetch_row(result); if (row != NULL ) { num_fields = mysql_num_fields(result); lengths = mysql_fetch_lengths(result); for (int i = 0 ; i < num_fields; i++) { printf ("Column %u is %lu bytes in length.\n" , i, lengths[i]); } } int num_fields = mysql_num_fields(res);while ((row = mysql_fetch_row(res))) { for (int i = 0 ; i < num_fields; i++) { printf ("%s " , row[i] ? row[i] : "NULL" ); } printf ("\n" ); }
资源回收/关闭连接
1 2 3 4 5 void mysql_free_result (MYSQL_RES* result) ;void mysql_close (MYSQL* mysql) ;
字符编码
1 2 3 4 5 6 7 const char * mysql_character_set_name (MYSQL* mysql) int mysql_set_character_set (MYSQL* mysql, char * csname)
事务操作
我们处理数据不是说添加一次就算完了,可能需要添加、删除、查找等一系列操作。这一系列操作序列在mysql中就称作事务 ,mysql中还提供对事务的回滚(roll back ),就是说事务当中的某次操作失败了,就可以回滚到事务处理前的状态,回到对数据库什么也没动的状态。
1 2 3 事务 ---- SELECT ---- INSERT ---- DELETE ^ roll back
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 my_bool mysql_autocommit (MYSQL *mysql, my_bool mode) 参数: 如果模式为“1”,启用autocommit模式;如果模式为“0”,禁止autocommit模式。 返回值 如果成功,返回0,如果出现错误,返回非0值。 my_bool mysql_commit (MYSQL* mysql) ; 返回值: 成功: 0 , 失败: 非0 my_bool mysql_rollback (MYSQL* mysql) 返回值: 成功: 0, 失败: 非0
打印错误信息
1 2 3 4 const char * mysql_error (MYSQL* mysql) ;unsigned int mysql_errno (MYSQL* 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 #include <stdio.h> #include <mysql/mysql.h> int main () { const char * host = "192.168.66.1" ; const char * user = "root" ; const char * passwd = "root" ; const char * db = "test" ; unsigned int port = 3306 ; const char * unix_socket = NULL ; unsigned long client_flag = 0 ; MYSQL* mysql = mysql_init(NULL ); mysql = mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag); if (mysql != NULL ) { printf ("连接成功\n" ); } else { perror("连接失败" ); return -1 ; } if (mysql_query(mysql, "SELECT * FROM user" ) == 0 ) { printf ("查询成功\n" ); MYSQL_RES* result = mysql_store_result(mysql); int num = mysql_num_fields(result); printf ("字段数为: %d\n" , num); MYSQL_FIELD* fields = mysql_fetch_fields(result); MYSQL_ROW row; while ((row = mysql_fetch_row(result))) { for (int i = 0 ; i < num; i++) printf ("%s: %s\n" , fields[i].name, row[i] ? row[i] : "NULL" ); } } else { perror("查询失败" ); } mysql_close(mysql); return 0 ; }
封装