Linux下访问数据库
声明:本文只简单描述Linux系统下访问mysql数据库的步骤,关于连接上数据库之后的简单的对于数据库的增删改查等操作只是稍微提及,关于增删改查的语句书写,本文不再讲述。
一般来说,访问数据库有如下几个步骤:
1.初始化mysql环境
2.连接数据库
3.执行sql语句
4.获取查询结果
5.显示结果
6.关闭数据库
7.释放mysql环境
针对以上7个步骤,接下来重点描述以下者7个步骤中所需要做的工作和所使用到的函数。
1.初始化mysql环境
作为连接数据库前的准备工作,这个步骤要做的事情其实还是很多的。首先需要创建MYSQL变量,用来存储与连接有关的数据信息。其结构体的结构非常复杂,不需要过多的理解。在实际使用时有着其固定的使用方法,只需记住就行。
typedef struct st_mysql
{
NET net;
gptr connector_fd;
char *host, *user,*passwd,*unix_socket,*server_version, *host_info,*info,*db;
unsigned int port,client_flag,server_capabilities;
unsigned int protocol_version;
unsigned int field_count;
unsigned int server_status;
unsigned long thread_id;
my_ulonglong affected_rows;
my_ulonglong insert_id;
my_ulonglong extra_info;
unsigned long packet_length;
enum mysql_status status;
MYSQL_FIELD *fields;
MEM_ROOT field_alloc;
my_bool free_me;
my_bool reconnect;
struct st_mysql_options options;
char scramble_buff[9];
struct charset_info_st *charset;
unsigned int server_language;
}MYSQL;
除此之外,此阶段还有两个函数也至关重要,mysql_init()函数和mysql_library_init()函数。
MYSQL *mysql_init(MYSQL *mysql);
功能:用来初始化一个连接句柄
若函数成功执行,则返回一个MYSQL类型的指针,失败则返回NULL。
int mysql_library_init(int argc,char **argv,char **groups);
功能:用来初始化mysql库
关于这两个函数的参数含义此处不做解释,因为本鸟也不知道,唯一知道的就是这么用就对了,实际使用时给三个参数赋值为0,NULL,NULL,具体使用方法会在最后的案例中提及。
还有一个与mysql_library_init()函数相对应的函数mysql_library_end(),用来关闭服务器端数据库。这两个函数必须放在一起使用,先初始化,最后再关闭数据库,如果只初始化不关闭,那么之前申请的一块内存将会一直存在,容易导致内存泄漏。
2.连接数据库
连接数据库部分涉及到两个函数,分别是mysql_real_connect()函数和mysql_select_db()函数。
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 clientflag);
功能:用来连接数据库
参数说明:
mysql:之前定义的MYSQL变量
host:MYSQL服务器的地址
user:登陆用户名
passwd:登陆密码
db:要连接的数据库
port:MYSQL服务器的TCP服务端口
unix_socket:unix连接方式,为NULL时表示不使用socket或管道机制
clientflag:mysql运行为ODBC数据库的标记,一般取0
返回值:成功,返回*mysql指针,失败,返回NULL
此函数的参数较多,实际使用时不会给每个参数都赋值的,只需要记住最常被赋值的几个参数即可。
int mysql_select_db(MYSQL *mysql,const char *db);
功能:使得由db指定的数据库成为由mysql指定的连接上的默认数据库
返回值:成功,返回0;失败,返回一个非0值。
错误代码:
CR_COMMANDS_OUT_OF_SYNC:以不恰当的顺序执行了命令
CR_SERVER_GONE_ERROR:mysql服务器不可用
CR_SERVER_LOST:在查询过程中与服务器的连接丢失
CR_UNKNOWN_ERROR:出现未知错误
3.执行sql语句
当数据库连接成功之后就可以对数据库中的数据进行增删改查等操作了,这些增删改查的语句本鸟不再书写,相信大家都会吧。但是,这些语句并不是独自出现的,而是把它存储在一个缓冲区里,作为函数参数使用,此函数为:
int mysql_query(MYSQL *mysql,const char *q);
功能:执行sql语句
参数:第一个参数为mysql结构体,第二个参数为操作命令。
还有一个可用来执行sql语句的函数:
int mysql_real_query(MYSQL *mysql,const char *query,unsigned long length);
功能:进行数据库查询。执行由query指向的sql查询,正常情况下,字符串必须包含一条sql语句,而且不应该为语句添加终结分号。
参数说明:
mysql:MYSQL变量
query:查询语句
length:查询语句的长度
以上两个函数都是用来进行数据库查询的函数。不同之处在于,对于包含二进制数据的查询,必须使用mysql_real_query()函数,这是因为 二进制数据可能会包含‘\0’字符,同时,mysql_real_query()函数执行速度快,这是因为此函数不会在查询字符串上调用strlen()函数。
执行sql语句后,我们通过调用mysql_store_result()或mysql_use_result()函数返回的MYSQL_RES变量获取查询结果数据。
MYSQL_RES *mysql_store_result(MYSQL *mysql);
MYSQL_RES *mysql_use_result(MYSQL *mysql);
这两个函数分别代表了获取查询结果的两种方式。
第一种,调用mysql_store_result()函数将从mysql服务器查询的所有数据都存储到客户端,然后读取;
第二种,调用mysql_use_result()初始化检索,以便于后面一行一行的读取结果集,而它本身并没有从服务器读取任何数据,这种方式较之第一种速度更快且所需内存更少,但它会绑定服务器,阻止其他线程更新任何表,而且必须重复执行mysql_fetch_row()读取数据,直至返回NULL,否则未读取的行会在下一次查询时作为结果的一部分返回,故经常我们使用mysql_store_result()。
4.获取查询结果
我们把执行完sql语句的返回的结果称为结果集,其用一个MYSQL_RES结构体来存储。本部分的主要内容就是从返回的结果集里获取查询结果。
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;
unsigned long *lengths;
MYSQL *handle;
my_bool eof;
}MYSQL_RES;
这样的结构体着实令本鸟头大。
MYSQL_FIELD和MYSQL_ROWS结构体来获取。这个结构体包含着结果集中的字段名、字段类型、字段大小等信息,可以通过重复调用mysql_fetch_fields()函数来获得所有字段的信息,即列信息或列数据。
typedef struct st_mysql_field
{
char *name;
char *table;
char *def;
enum enum_field_types type;
unsigned int length;
unsigned int max_length;
unsigned int flags;
unsigned int decimals;
} MYSQL_FIELD;
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
功能:读取结果集字段
与之对应的是MYSQL_ROWS结构体里的mysql_fetch_row()函数,此函数用来获得结果集中的行信息。
MYSQL_ROW *mysql_fetch_row(MYSQL_RES *res);
功能:读取结果集数据
返回值:该函数返回MYSQL_ROW型的变量,即字符串数组,假设其为row,则row[i]为第i个字段的值,当到结果集尾部时,此函数返回NULL。
刚才说到mysql_fetch_row()函数是用来获取数据集中的数据信息,它只能一行一行的来获取,所以还得有个函数用来统计结果集中的行数。同样的,也得用一个函数来获取结果集中的字段的数量。
unsigned int mysql_num_fields(MYSQL_RES *res);
功能:获取结果集中字段的数量
unsigned int mysql_num_rows(MYSQL_RES *res);
功能:获取结果集中行数
结果集使用完毕后,还需释放掉结果集,避免内存泄漏。
void mysql_free_result(MYSQL_RES *res);
5.关闭数据库
不需要继续查询mysql数据库时,应及时关闭数据库连接。
void mysql_close(MYSQL *sock);
sock为连接函数返回的变量。
6.释放mysql环境
在初始化阶段中提到了一个与mysql_library_init()函数相对应的函数mysql_library_end(),此函数用来及时释放mysql环境,来终止使用mysql数据库。
案例:MysqlDemo.c
本案例主要是通过远程访问数据库来对数据库里的数据信息进行增删改查等操作。在正式编码之前,我们首先需要直到关于本案例所要用到的数据库的基本信息。本案例所使用的数据库为StaffDB,该数据库里有3张表,分别为Department(部门)、Work(职务)、Staff(员工信息),每张表的结构和数据如下所示:
Department(部门):
Work(职务):
Staff(员工):
这3张表的截图都是在Windows系统下所截取的,我们就是要通过案例来对这些数据加以操作。
MysqlDemo.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <mysql/mysql.h>
//查询
int Select_sql(MYSQL *p_sock)
{
//声明缓冲区并初始化
char buffer[1024]={0};
memset(buffer,0x00,1024);
snprintf(buffer,sizeof(buffer),"%s","select * from Department");
//执行sql语句
int ret = mysql_query(p_sock,buffer);
if(ret != 0)
{
printf("查询错误:%s\n",mysql_error(p_sock));
return -1;
}
//结果集
MYSQL_RES *res;
//数据行
MYSQL_ROW row;
//记录结果的行数
int rows = 0;
//记录结果的列数
int columns = 0;
//获取查询结果
res = mysql(store_result(p_sock));
if(res == NULL)
{
printf("获取结果集错误:%s\n",mysql_error(p_sock));
return -1;
}
//获取查询结果的行数
rows = mysql_num_rows(res);
if(rows < 0)
{
printf("获取查询结果的行数错误:%s\n",mysql_error(p_sock));
return -1;
}
if(rows == 0)
{
printf("该查询结果中无数据!\n");
return 0;
}
//获取查询结果的列数
columns = mysql_num_fields(res);
if(rows < 0)
{
printf("获取查询结果的列数错误:%s\n",mysql_error(p_sock));
return -1;
}
//获取每一行数据
while((row = mysql_fetch_row(res)) != NULL)
{
int i;
for(i = 0;i < columns;i++)
{
printf("%s\t",rows[i]);
}
printf("\n");
}
//释放结果集所占用的空间
mysql_free_result(res);
return 0;}
}
//插入
int Insert_sql(MYSQL *p_sock)
{
char buffer[1024] = {0};
//sql语句
memset(buffer,0x00,1024);
snprintf(buffer,1023,"%s","insert into Department(Department_id,Department_name,Remark) value('D07','综合部','综合部')");
//执行sql语句
if(mysql_query(p_sock,buffer) != 0)
{
perror("mysql_query");
return -1;
}
return 0;
}
//更新
int Update_sql(MYSQL *p_sock)
{
char buffer[1024] = {0};
//sql语句
memset(buffer,0x00,1024);
snprintf(buffer,1023,"%s","update Department set Remark = "综合管理" where Department_id = 'D07'");
//执行sql语句
if(mysql_query(p_sock,buffer) != 0)
{
perror("mysql_query");
return -1;
}
return 0;
}
//删除
int Delete_sql(MYSQL *p_sock)
{
char buffer[1024] = {0};
//sql语句
memset(buffer,0x00,1024);
snprintf(buffer,1023,"%s","delete from Department where Department_id = 'D07'");
//执行sql语句
if(mysql_query(p_sock,buffer) != 0)
{
perror("mysql_query");
return -1;
}
return 0;
}
int main()
{
//按照文档中的步骤,首先进行对sql环境的初始化
//1.初始化sql环境
//定义MYSQL变量
MYSQL mysql,*p_mysql,*p_sock;
//初始化mysql句柄
p_mysql = mysql_init(&mysql);
if(p_mysql == NULL)
{
printf("初始化错误!\n");
return -1;
}
//初始化MySQL库
int ret = mysql_library_init(0,NULL,NULL);
if(ret ==0)
{
printf("初始化数据库成功!\n");
}
else
{
printf("初始化数据库失败!\n");
return -1;
}
if(p_mysql != NULL && ret == 0)
{
printf("初始化sql环境成功!\n");
}
//2.连接数据库
p_sock = mysql_real_connect(p_mysql,"127.0.0.1","root","(NavyBlue123)",NULL,0,NULL,0);
if(p_sock == NULL)
{
//输出错误原因
printf("连接错误:%s\n",mysql_error(p_mysql));
return -1;
}
//选择数据库
int r = mysql_swlect_db(p_sock,"StaffDB");
if(r != 0)
{
printf("选择数据库出错:%s\n",mysql_error(p_mysql));
return -1;
}
//设置编码格式,注意,此处一定要设置编码格式,不然最后的查询结果中的中文会显示乱码
mysql_query(&mysql,"SET NAMES utf8");
if(p_sock != NULL && r == 0)
{
printf("数据库连接成功!\n");
}
//3.执行sql语句,此部分我们另写函数实现
//查询部分我们选择查询3张表的整体信息
Select_sql(p_sock);
//插入部分我们选择给Staff表中插入一条新的员工信息
Insert_sql(p_sock);
//修改,即更新
Update_sql(p_sock);
//删除部分我们选择删除新插入到Staff表中的那条员工信息
Delete_sql(p_sock);
//4.获取查询结果,此部分会在执行sql语句的函数里一并处理
//5.关闭数据库
mysql_close(&mysql);
//6.释放sql环境,终止使用MySQL库
mysql_library_end();
return 0;
}
由于本鸟的Mysql在安装的时候丢失了重要的文件,所以此文件无法运行,还希望大家在闲余时间能够亲自跑一下代码,熟悉一下连接过程为好。