MySql数据库API编程
初始化
初始化函数原型:MYSQL *mysql_init(MYSQL *mysql)
处理错误码的函数:unsigned int mysql_errno(MYSQL *mysql)
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"
int main()
{
//MYSQL *mysql_init(MYSQL *mysql)
MYSQL *mysql = mysql_init(NULL);
if(mysql==NULL){
printf("mysql init error\n");
return -1;
}
printf("mysql init ok\n");
return 0;
}
使用ldd
命令可以查看该可执行文件运行所依赖的库文件。
编译:makefile 管理
src = $(wildcard *.c)
target = $(patsubst %.c, %, $(src))
inc_path = /usr/include/mysql/
lib_path = /usr/lib64/mysql/
all: $(target)
%:%.c
gcc $< -o $@ -I$(inc_path) -L$(lib_path) -lmysqlclient -lstdc++ -lpthread -ldl -lrt
clean:
-rm -rf $(target)
.PHONY: all clean
连接数据库、关闭数据库
连接数据库函数原型: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)
关闭数据库函数原型:void mysql_close(MYSQL *mysql)
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"
int main()
{
//初始化
//MYSQL *mysql_init(MYSQL *mysql)
MYSQL *mysql = mysql_init(NULL);
if(mysql==NULL){
printf("mysql init error\n");
return -1;
}
printf("mysql init ok\n");
//连接mysql数据库
//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 *conn = mysql_real_connect(mysql, "192.168.10.145", "root", "123456", "scott", 0, NULL, 0);
if(conn==NULL){
printf("mysql_real_connect error,[%s]\n", mysql_error(mysql));
return -1;
}
printf("connect mysql OK, [%p], [%p]\n", mysql, conn);
//关闭数据库连接
mysql_close(conn);
return 0;
}
查询表数据
mysql_query
函数不单单能完成查询sql的功能,还能完成非select语句在c程序中的执行。
并且该函数本身直接支持静态SQL。查询以\0结尾的字符串。
如果语句中包含二进制数据,则需要调用mysql_real_query来执行查询语句。
注意: mysql_query
执行的SQL语句不应为语句添加终结分号(‘;’)或“\g”。
函数原型:int mysql_query(MYSQL *mysql, const char *query);
成功返回0,失败返回非0
//mysql执行sql语句
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"
int main()
{
//初始化
//MYSQL *mysql_init(MYSQL *mysql)
MYSQL *mysql = mysql_init(NULL);
if(mysql==NULL){
printf("mysql init error\n");
return -1;
}
printf("mysql init ok\n");
//连接mysql数据库
//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 *conn = mysql_real_connect(mysql, "192.168.10.145", "root", "123456", "scott", 0, NULL, 0);
if(conn==NULL){
printf("mysql_real_connect error,[%s]\n", mysql_error(mysql));
return -1;
}
printf("connect mysql OK, [%p], [%p]\n", mysql, conn);
//执行sql语句
//int mysql_query(MYSQL *mysql, const char *query)
char sSQL[255] = "insert into mytest values(1, 'xiaohuang')";
int ret = mysql_query(conn, sSQL);
if(ret!=0){
printf("mysql_query error, [%s]\n", mysql_error(mysql));
}
printf("mysql_query ok\n");
//关闭数据库连接
mysql_close(conn);
return 0;
}
获取结果集
一种方式是通过mysql_store_result()
将整个结果集全部取回来。
另一种方式调用mysql_use_result()
初始化获取操作,但暂时不取回任何记录。视结果集的条目数选择获取结果集的函数。
两种方法均通过mysql_fetch_row()来访问每一条记录。
函数原型:MYSQL_RES *mysql_store_result(MYSQL *mysql)
成功返回MYSQL_RES
结果集指针,失败返回NULL。
MYSQL_RES
是一个结构体类型,可以从mysql.h头文件中找到该结构体的定义
MYSQL_RES *result = mysql_store_result(mysql);
if (result == NULL) {
ret = mysql_errno(mysql);
printf("mysql_store_result error: %s\n", mysql_error(mysql));
return ret;
}
该函数调用成功,则SQL查询的结果被保存在result中,但我们不清楚有多少条数据。所以应使用游标的方式将结果集中的数据逐条取出。
解析结果集
通过游标一行一行fetch结果集中的数据。根据游标使用的一般特性,应使用循环结构,到达结尾或者出错,返回NULL。
函数原型:MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
char **mysql_fetch_row(){
char **tmp = (char **) malloc(sizeof(char *) * 8);
for (i = 0; i < 8; i++) {
tmp[i] = (char *)malloc(50);
}
strcpy(tmp[0], "7369");
strcpy(tmp[1], "SMITH");
strcpy(tmp[2], "CLERK");
...
return tmp;
}
成功返回下一行的MYSQL_ROW结构。
如果没有更多要检索的行或出现了错误,返回NULL
select * from emp
可以看到emp表一共有8列数据。循环将每行上每一列的数据显示到屏幕。
MYSQL_ROW row = NULL; //typedef char **MYSQL_ROW;
while ((row = mysql_fetch_row(result))) {
printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7]);
}
MYSQL_ROW
的本质是 typedef char ** MYSQL_ROW;
释放结果集
结果集处理完成,应调用对应的函数释放所占用的内存。
函数原型:void mysql_free_result(MYSQL_RES *result);
成功释放参数传递的结果集。没有失败情况。
mysql_free_result(result);
获取列数
函数原型:
unsigned int mysql_field_count(MYSQL *mysql)
从mysql句柄中获取有多少列。
unsigned int mysql_num_fields(MYSQL_RES *result)
从返回的结果集中获取有多少列。
int num = mysql_field_count(connect);
while (row = mysql_fetch_row(result)) {
for (i = 0; i < num; i++) {
printf("%s\t", row[i]);
}
printf("\n");
//printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7]);
}
获取表头
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result) ;
全部获取
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result) ;
获取单个
MYSQL_FIELD也是一个结构体类型,其内部保存了选择列表项的信息,其中的name成员变量就保存着列名。可从头文件mysql.h中找到其定义:
MYSQL_FIELD *fields = NULL;
fields = mysql_fetch_fields(result); //得到表头的结构体数组
for (i = 0; i < num; i++) { //已通过 mysql_field_count 获取了总列数
printf("%s\t", fields[i].name); //每一列的列名保存在name成员中
}
printf("\n");
测试示例
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"
int main(){
//初始化
//MYSQL *mysql_init(MYSQL *mysql)
MYSQL *mysql = mysql_init(NULL);
if(mysql==NULL){
printf("mysql init error\n");
return -1;
}
printf("mysql init ok\n");
//连接mysql数据库
//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 *conn = mysql_real_connect(mysql, "192.168.10.145", "root", "123456", "scott", 0, NULL, 0);
if(conn==NULL){
printf("mysql_real_connect error,[%s]\n", mysql_error(mysql));
return -1;
}
printf("connect mysql OK, [%p], [%p]\n", mysql, conn);
//执行sql语句
//int mysql_query(MYSQL *mysql, const char *query)
char sSQL[255] = "select * from mytest";
int ret = mysql_query(conn, sSQL);
if(ret!=0){
printf("mysql_query error, [%s]\n", mysql_error(mysql));
}
printf("mysql_query ok\n");
//获取结果集
//MYSQL_RES *mysql_store_result(MYSQL *mysql)
MYSQL_RES *results = mysql_store_result(conn);
if(results==NULL)
{
printf("mysql_store_result error,[%s]\n", mysql_error(mysql));
return -1;
}
printf("mysql_store_result ok\n");
int i = 0;
//获取列数
// unsigned int mysql_num_fields(MYSQL_RES *result)
unsigned int num = mysql_num_fields(results);
//获取表头信息---列名
//MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)
MYSQL_FIELD *fields = mysql_fetch_fields(results);
if(fields==NULL)
{
printf("mysql_fetch_fields error,[%s]\n", mysql_error(mysql));
return -1;
}
//打印表头信息
printf("+------+-----------+\n");
for(i=0; i<num; i++)
{
printf("%s\t", fields[i].name);
}
printf("\n");
printf("+------+-----------+\n");
//获取结果集中每一行记录
MYSQL_ROW row;
while((row=mysql_fetch_row(results)))
{
for(i=0; i<num; i++)
{
printf("%s\t", row[i]);
}
printf("\n");
}
printf("+------+-----------+\n");
//释放结果集
//void mysql_free_result(MYSQL_RES *result)
mysql_free_result(results);
//关闭数据库连接
mysql_close(conn);
return 0;
}
MySql 客户端工具实现
MySQL基础类API函数,可以编写程序实现简单的sqlplus/mysql
工具的功能。
-
仿照mysql工具,应在连接数据库成功之后,在一个while循环中不断的接受用户输入的SQL语句。定义
char sqlbuf[1024]
存储用户输入的SQL语句。初始化该buf,并提示用户输入SQL语句。使用gets函数在循环中动态接收用户输入。while (1) { memset(sqlbuf, 0, sizeof(sqlbuf)); printf("\nYourSQL> "); fgets(sqlbuf, sizeof(sqlbuf), stdin); }
-
在
mysql_query(connect, sqlbuf)
之前,如果用户输入了exit
那么程序直接结束。 -
在执行完
mysql_query(connect, sqlbuf)
之后,应该判别用户输入的是否为select语句。如不是select语句不需要查询结果集、处理结果集等繁复操作。 -
如用户输入的是有结果集的SQL语句,将获取列数、获取结果集、获取表头、解析结果集、释放结果集等相关代码一起并入
if (strncmp(sqlbuf, "select", 6))
中。 -
中文问题:修改mysql_real_connect()参数,连接到表中有中文数据的数据库,如mydb2,执行程序,测试显示中文出现乱码。我们可以使用mysql_query函数来解决该问题。
在
while (1)
之前使用ret = mysql_query(mysql, "set names utf8");
来设置查询属性(也可以加到while中)。表示在查询的时候使用utf8的形式进行查询。或者获取当前使用的字符集:
const char *mysql_character_set_name(MYSQL *mysql)
mysql_set_character_set(mysql, "utf8");
//模拟mysql客户端程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mysql.h"
int main()
{
int ret = 0;
//mysql初始化---mysql_init
MYSQL *mysql = mysql_init(NULL);
if(mysql==NULL){
ret = mysql_error(mysql);
printf("mysql_init error:%d\n", ret);
return -1;
}
printf("init ok...\n");
//连接数据库
MYSQL *conn = mysql_real_connect(mysql, "localhost", "root", "123456", "scott", 0, NULL, 0);
if(conn==NULL){
printf("connect mysql db error, [%s]\n", mysql_error(mysql));
return -1;
}
printf("connect ok...\n");
//获取当前进程使用的字符集
printf("before:[%s]\n", mysql_character_set_name(conn));
//设置字符集为utf8格式
mysql_set_character_set(conn, "utf8");
printf("after:[%s]\n", mysql_character_set_name(conn));
int i;
int n;
int ret;
int num;
char *p;
char buf[1024];
MYSQL_RES *results;
MYSQL_FIELD *fields;
MYSQL_ROW row;
//进入循环等待用户输入sql语句并执行sql语句
while(1){
//打印提示符
write(STDOUT_FILENO, "mysql> ", strlen("mysql> "));
//读取用户输入
memset(buf, 0x00, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
//1-去掉末尾的;
p = strrchr(buf, ';');
if(p!=NULL){
*p = '\0';
}
//2-去掉回车
if(buf[0]=='\n') {
continue;
}
//去掉最前面的几个空格
for(i=0; i<strlen(buf); i++){
if(buf[i]!=' ')
{
break;
}
}
n = strlen(buf);
memmove(buf, buf+i, n-i+1); //+1表示多拷贝一个\0
printf("[%s]\n", buf);
//若输入的是退出: exit EXIT quit QUIT
if(strncasecmp(buf, "exit", 4)==0 || strncasecmp(buf, "quit", 4)==0){
mysql_close(conn);
exit(0);
}
//执行sql语句
ret = mysql_query(conn, buf);
if(ret!=0){
printf("%s\n", mysql_error(conn));
continue;
}
//若用户输入的不是select查询
if(strncasecmp(buf, "select", 6)!=0){
printf("Query OK, %ld row affected\n", mysql_affected_rows(conn));
continue;
}
//下面是select查询的情况
//获取结果集
results = mysql_store_result(conn);
if(results==NULL){
printf("%s\n", mysql_error(conn));
continue;
}
//获取列数
num = mysql_num_fields(results);
//获取表头---列名
fields = mysql_fetch_fields(results);
if(fields==NULL){
printf("%s\n", mysql_error(conn));
mysql_free_result(results);
continue;
}
//打印表头
printf("+----------+-----------+\n");
for(i=0; i<num; i++){
printf("%s\t", fields[i].name);
}
printf("\n");
printf("+----------+-----------+\n");
//循环获取每一行记录
while(row=mysql_fetch_row(results)){
for(i=0; i<num; i++)
{
printf("%s\t", row[i]);
}
printf("\n");
}
printf("+----------+-----------+\n");
//释放结果集
mysql_free_result(results);
}
//关闭数据库连接
mysql_close(conn);
return 0;
}