C语言实现程序连接数据库并实现简单的嵌入式服务器

我们可以直接访问数据库,当然我们也需要在程序中连接数据库。
接下来我将介绍嵌入式MySQL服务器库。
使用嵌入式 MySQL 服务器库, 能够在客户端应用程序中使用具备全部特性的 MySQL 服务器。 主要优点在于,增加了速度,并使得嵌入式应用程序的管理更简单。嵌入式服务器库是以 MySQL 的客户端/ 服务器版本为基础的, 采用 C/C++语言编写。 其结果是嵌入式服务器也是用 C/C++语言编写的。 在其他语言中, 嵌入式服务器不可用。
具体简单步骤:

1.获取或者初始化MYSQL结构

首先MYSQL是一个结构类型,该结构代表 1 个数据库连接的句柄。 几乎所有的 MySQL 函数均使用它。
函数介绍

MYSQL *mysql_init(MYSQL *mysql)
/*
	分配或初始化与 mysql_real_connect()相适应的 MYSQL 对象。 如果 mysql 是 NULL 指针,
	该函数将分配、 初始化、 并返回新对象。 否则, 将初始化对象, 并返回对象的地址。 如果
	mysql_init()分配了新的对象, 当调用 mysql_close()来关闭连接时。 将释放该对象。
	初始化的 MYSQL*句柄。 如果无足够内存以分配新的对象, 返回 NULL。
*/

我们来获得一个句柄

MYSQL *mysql =mysql_init(NULL);	//获得数据库连接的句柄,分配或初始化与 mysql_real_connect()相适应的 MYSQL 对象
if(mysql == null){
	printf("mysql_init error!\n");
	return -1;
}

2.尝试与数据库引擎建立连接

我们会用到一个函数
函数介绍

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_real_connect()尝试与运行在主机上的 MySQL 数据库引擎建立连接。 在你能够执行
需要有效 MySQL 连接句柄结构的任何其他 API 函数之前, mysql_real_connect()必须成功完成。
第 1 个参数应是已有 MYSQL 结构的地址。 调用 mysql_real_connect()之前, 必须调
用 mysql_init()来初始化 MYSQL 结构。 
“host”的值必须是主机名或 IP 地址。 如果“host”是 NULL 或字符串"localhost", 连接
将被视为与本地主机的连接。
“user”参数包含用户的 MySQL 登录 ID。 如果“user”是 NULL 或空字符串"", 用户将
被视为当前用户。 
“passwd”参数包含用户的密码。 如果“passwd”是 NULL, 仅会对该用户的(拥有 1
个空密码字段的) 用户表中的条目进行匹配检查。 
“db”是数据库名称。 如果 db 为 NULL, 连接会将默认的数据库设为该值。
如果“port”不是 0, 其值将用作 TCP/IP 连接的端口号。 
如果 unix_socket 不是 NULL, 该字符串描述了应使用的套接字或命名管道。 
client_flag 的值通常为 0, 
*/

我们来尝试连接

mysql = mysql_real_connect(mysql,"localhost(主机)","root(用户)","password(密码)","databases(数据库名称)",3306,NULL,0);
if(mysql == NULL){
	printf("mysql_real_connect error:%s\n",mysql_error(mysql));
	//mysql_error()这个函数返回上次调用的MYSQL函数的错误信息,是一串以null终结的字符串
	return -1;
}

3.执行SQL语句

连接上数据库后,我们就可以执行SQL语句了,这些语句可以是DDL,DQL,DML等等语句,由用户自己输入。
函数介绍

	mysql_query(MYSQL *mysql,const char *sql);
	/*
	执行由“Null 终结的字符串”查询指向的 SQL 查询。 正常情况下, 字符串必须包含 1 条 SQL
语句, 而且不应为语句添加终结分号(‘;’) 或“\g”。 如果允许多语句执行, 字符串可包含多条由分号隔开的语句。
	如果希望了解查询是否应返回结果集, 可使用 mysql_field_count()进行检查
	如果查询成功, 返回 0。 如果出现错误, 返回非 0 值。
	*/

接下来我们自己输入想要执行的SQL语句

char query[1024]={};
printf("mysql>");
gets(query);
if(strcmp(query,"quit") == 0 || strcmp(query,"exit") == 0){
	//当输入的sql语句是quit或者exit时,退出该嵌入式服务器
	printf("Bye!\n");
	break;
}
mysql_query(mysql,"set names utf8");
//这行代码的作用是当设置环境为utf-8编码,
//如果不设置,很有可能中文字符无法正常显示,会显示为一堆乱码
int ret = mysql_query(mysql,query);
//执行sql语句
if(ret != 0){
	printf("mysql_query error:%s\n",mysql_error(mysql));
	continue;
}

4.获得结果集

当我们执行完一条sql语句后,可能有结果集,也有可能没有结果集,所以接下来我们将会用个函数来接收一个结果集。
函数介绍

MYSQL_RES * mysql_store_result(MYSQL *mysql);
/*
对于成功检索了数据的每个查询(SELECT、 SHOW、 DESCRIBE、 EXPLAIN、 CHECKTABLE 等) ,
必须调用 mysql_store_result()或 mysql_use_result()
于其他查询, 不需要调用 mysql_store_result()或 mysql_use_result(), 但是如果在任何情
况下均调用了 mysql_store_result(), 它也不会导致任何伤害或性能降低。 通过检查
mysql_store_result()是否返回 0,
如果查询未返回结果集, mysql_store_result()将返回 Null 指针(例如, 如果查询是 INSERT
语句) 。
如果读取结果集失败, mysql_store_result()还会返回 Null 指针。 通过检查 mysql_error()是
否返回非空字符串, mysql_errno()是否返回非 0 值, 或 mysql_field_count()是否返回 0, 可
以检查是否出现了错误。
如果未返回行, 将返回空的结果集。 (空结果集设置不同于作为返回值的空指针) 。 
*/

那我们看一下执行完sql语句后的结果集如何
我们还需要介绍一下另外一个结构体MYSQL_RES,该结构代表返回行的查询结果(SELECT, SHOW, DESCRIBE, EXPLAIN) 。

MYSQL *result = mysql_store_result(mysql);
if(result == NULL){
	if(mysql_errno(mysql) != 0){
		printf("mysql_store_result error:%s\n",mysql_error(mysql));
		return -1;	
	}else{
		printf("Query OK!\n");
		continue;
	}
	/*
		有必要解释这几行代码,当result为空的时候,会有两种情况,第一种就是出现了错误,
//那我们需要显示错误信息,当发生错误时,mysql_errno()会返回上次调用的 MySQL 函数的错误编号,
//这个编码为非0值,所以当mysql_errno(mysql) != 0时就是表示发生了错误。
		所以当mysql_errno(mysql) == 0时表示没有出现错误,但是没有结果集,
//比如当我们执行DML,DDL,TCL语句时就不会反回结果,这回返回影响了几条记录,比如"Query OK, 1 row affected (0.00 sec)"
	*/
}

5.显示结果集

当我们获得结果集后,就需要显示结果集了,首先我们需要知道这个结果集中一行(即一条记录,元组)的信息,这时候我们又有了另外两个结构体类型 MYSQL_ROWh和MYSQL_FIELD。
MYSQL_ROW这是 1 行数据的“类型安全”表示。 它目前是按照计数字节字符串的数组实施的。 (如果字段值可能包含二进制数据, 不能将其当作由 Null 终结的字符串对待, 这是因为这类值可能会包含 Null 字节) 。 行是通过调用 mysql_fetch_row()获得的。
MYSQL_FIELD该结构包含关于字段的信息, 如字段名、 类型和大小。 这里详细介绍了其成员。 通过重复调用 mysql_fetch_field(), 可为每个字段获得 MYSQL_FIELD 结构。 字段值不是该结构的组成部份, 它们包含在 MYSQL_ROW 结构中。

接下来我们看一下该如何显示结果集
函数介绍

unsigned int mysql_num_fields(MYSQL_RES *result);
//返回结果集中的行数。注意, 你可以从指向结果集的指针或指向连接句柄的指针获得行数。
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);
//对于结果集, 返回所有 MYSQL_FIELD 结构的数组。 每个结构提供了结果集中 1 列的字段定义。
my_ulonglong mysql_num_rows(MYSQL_RES *result);
//返回结果集中的行数。
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
//检索结果集的下一行。 在 mysql_store_result()之后使用时, 如果没有要检索的行,
//mysql_fetch_row()返回 NULL。 在 mysql_use_result()之后使用时, 如果没有要检索的行或出现了
//错误, mysql_fetch_row()返回 NULL。

具体代码实现

unsigned int fields = mysql_num_fields(result);
MYSQL_ROW record;
MYSQL_FIELD *fl = mysql_fetch_field(result);
size_t i;
printf("**************************\n");
for(i=0;i<fields;i++){
	printf("%-15s ",fl[i].name);
}
printf("\n");
while(record = mysql_fetch_row(result)){
	for(i=0;i<fileds;i++){
		printf("%-10s  ",record[i]);
	}
	printf("\n");
}
my_ulonglong rows = mysql_num_rows(result);
printf("%lu rows in set (0.012 sec)\n",(unsigned long int)(rows));

6.释放资源,关闭连接

当我们完成数据库的操作后,需要释放资源和关闭连接,否则会出现其他许多问题。
函数介绍

void mysql_free_result(MYSQL_RES *result);
//释放由 mysql_store_result()、 mysql_use_result()、 mysql_list_dbs()等为结果集分配的内存。
//完成对结果集的操作后, 必须调用 mysql_free_result()释放结果集使用的内存
void mysql_close(MYSQL *mysql);
//关闭前面打开的连接。 如果句柄是由 mysql_init()或 mysql_connect()自动分配的,
//mysql_close()还将解除分配由 mysql 指向的连接句柄。

最后我们关闭连接,释放资源

if(result != NULL){	
//如果当我们执行的第一句sql语句就是exit或者quit时,此时result仍未null,
//那这时候不需要释放,如果强行释放就会产生段错误.
	mysql_free_result(result);
}
mysql_close(mysql);

7.全部源代码

最后我们以这份源代码收尾

#include <mysql/mysql.h>
#include <stdio.h>


int main(){
	MYSQL *mysql = mysql_init(NULL);
	if(mysql == NULL){
		printf("mysql_init error!\n");
		return -1;
	}

	mysql = mysql_real_connect(mysql,"localhost","root","123456","test",3306,NULL,0);
	//这里需要根据每个数据库的具体数据来写参数
	if(mysql == NULL){
		printf("mysql_real_connect error:%s\n",mysql_error(mysql));
		return -1;
	}
	MYSQL_RES *result=NULL;
	while(1){
		char query[1024] = {};
		printf("mysql>");
		gets(query);
		if(strcmp(query,"quit") == 0 || strcmp(query,"exit") == 0){
			printf("Bye\n");
			break;
		}
		mysql_query(mysql,"set names utf8");
		int ret = mysql_query(mysql,query);
		if(ret != 0){
			printf("mysql_query error:%s\n",mysql_error(mysql));
			continue;
		}
		result = mysql_store_result(mysql);	//获得结果集
		if(result == NULL){
			if(mysql_errno(mysql) != (unsigned int)(0)){
				printf("mysql_store_result error:%s\n",mysql_error(mysql));
			 	return -1;
			}else{
				continue;	
			}
		}
		unsigned int fields = mysql_num_fields(result);
		MYSQL_ROW record;
		MYSQL_FIELD *fl = mysql_fetch_field(result);
		size_t i;
		printf("**************************\n");
		for(i=0;i<fields;i++){
			printf("%-15s ",fl[i].name);	
		}
		printf("\n");
		while(record = mysql_fetch_row(result)){
			for(i=0;i<fields;i++){
				printf("%-10s 	",record[i]);	
			}
			printf("\n");
		}
		my_ulonglong rows = mysql_num_rows(result);
		printf("%lu rows in set (0.012 sec)\n",(unsigned long int)(rows));
	}
	if(result!=NULL){
		mysql_free_result(result);
	}
	mysql_close(mysql);
	return 0;	
}

在运行这段程序前,我们还需要下载一个库libmysqlclient或者,平台不同要下载的东西也不同,但是大致都一样。

8.运行效果

最后的最后我们来看一下结果怎么样?
在这里插入图片描述
BYEBYE;

发布了14 篇原创文章 · 获赞 84 · 访问量 2651

猜你喜欢

转载自blog.csdn.net/weixin_42617375/article/details/103896758