c语言操作redis数据库

前言

redis(Remote Dictionary Server)是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库—来自维基百科。由于其读写性能高、数据结构丰富、支持主从复制、支持持久化等其他特性,使得redis成为当前最流行的key-value型数据库。本文将简单介绍c语言中如何操作redis数据库。

准备工作

hiredis安装

hiredis是redis官方推荐的基于C接口的客户端组件,它提供接口,供c语言调用以操作数据库。我们需要将hiredis安装到我们的系统中,在redis的源码包的deps/hiredis下就有它的源码,也可以另行下载hiredis
安装方法,进入deps/hiredis目录,执行命令:

1
2
3
make
make install
ldconfig #使动态库在系统中更新生效

接口介绍

  • 函数原型:redisContext redisConnect(const char ip, int port);
    说明:该函数用来连接redis数据库,参数为数据库的ip地址和端口,通常默认端口为6379。该函数返回一个redisContext对象。

  • 函数原型:void redisCommand(redisContext c, const char *format, …);
    说明:该函数执行redis命令,当然也包括由lua脚本组成的命令,返回redisReply对象。

    • 函数原型void freeReplyObject(void *reply);
      说明:释放redisCommand执行后返回的redisReply所占用的内存。

    • 函数原型:void redisFree(redisContext *c);
      说明:释放redisConnect()所产生的连接。

后面的示例操作基本都是基于以上函数。

  • redis reply对象:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* This is the reply object returned by redisCommand() */
    typedef struct redisReply {
    int type; /* 返回结果类型* */
    long long integer; /* 返回类型为整型的时候的返回值 */
    size_t len; /* 字符串长度 */
    char *str; /* 返回错误类型或者字符类型的字符串 */
    size_t elements; /* 返回数组类型时,元素的数量*/
    struct redisReply **element; /* 元素结果集合,redisReply对象 */
    } redisReply;

其中,返回类型有以下几种:

1
2
3
4
5
6
REDIS_REPLY_STRING 1 //字符串
REDIS_REPLY_ARRAY 2 //数组,多个reply,通过element数组以及elements数组大小访问
REDIS_REPLY_INTEGER 3 //整型
REDIS_REPLY_NIL 4 //空,没有数据
REDIS_REPLY_STATUS 5 //状态,str字符串以及len
REDIS_REPLY_ERROR 6 //错误,同STATUS

其他的我们暂时不过多介绍,下面通过一个简单的实例来看看这些接口的基本使用。

实例

实例通过redis数据库的hash表存储以下学生信息:

字段名 含义
sid 学号
name 学生姓名
gender 学生性别
major 专业

c语言描述如下:

1
2
3
4
5
6
7
8
9
10
#define SID_MAX_LENGHT 16
#define NAME_MAX_LENGHT 16
#define MAJOR_MAX_LENGHT 64
typedef struct Stu_Info_Struct
{
char sid[SID_MAX_LENGHT];
char name[NAME_MAX_LENGHT];
int gender;//0 male,1 female
char major[MAJOR_MAX_LENGHT];
}Stu_Info_Struct;

程序清单stu_manager.c如下:

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

/***************************************************************
* Copyright (C) 2017 All rights reserved.
*
* 文件名称:stu_manager.c
* 创 建 者:hyb
* 创建日期:2017年10月07日
* 描 述:
*
***************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<hiredis/hiredis.h>

/*宏定义*/
#define SID_MAX_LENGHT 16
#define NAME_MAX_LENGHT 16
#define MAJOR_MAX_LENGHT 64
#define CMD_MAX_LENGHT 256
#define REDIS_SERVER_IP "127.0.0.1"
#define REDIS_SERVER_PORT 6379
/*结构体定义*/
typedef struct Stu_Info_Struct
{
char sid[SID_MAX_LENGHT];
char name[NAME_MAX_LENGHT];
int gender;//0 male,1 female
char major[MAJOR_MAX_LENGHT];
}Stu_Info_Struct;

typedef enum STU_RESULT
{
SUCCESS=0,
FAILURE=1
}STU_RESULT;

/*函数*/
STU_RESULT addStu(Stu_Info_Struct *stu);/*添加信息*/
/*执行命令*/
STU_RESULT exeRedisIntCmd(char *cmd);
STU_RESULT quryStuBySid(char *sid);
STU_RESULT exeRedisStrCmd(char *cmd);
/**************************************
函数名:addStu
函数功能:添加学生信息
输入参数:stu 学生信息结构指针
输出参数:
返回值:STU_RESULT 成功或失败
************************************/
STU_RESULT addStu(Stu_Info_Struct *stu)
{
char cmd[CMD_MAX_LENGHT] = {0};
/*检查入参*/
if(NULL == stu)
{
printf("NULL pointer");
return FAILURE;
}
/*组装redis命令*/
snprintf(cmd,CMD_MAX_LENGHT,"hset stu:%s name %s gender %d major %s",
stu->sid,stu->name,stu->gender,stu->major);

/*执行redis命令*/
if(FAILURE == exeRedisIntCmd(cmd))
{
printf("add student %s,%s,%d,%s failure\n",stu->sid,stu->name,stu->gender,stu->major);
return FAILURE;
}
printf("add student %s,%s,%d,%s success\n",stu->sid,stu->name,stu->gender,stu->major);
return SUCCESS;
}
/**************************************
函数名:exeRedisIntCmd
函数功能:执行redis 返回值为int类型命令
输入参数:cmd redis命令
输出参数:redis 返回结构
返回值:STU_RESULT
*************************************/
STU_RESULT exeRedisIntCmd(char *cmd)
{
/*检查入参*/
if(NULL == cmd)
{
printf("NULL pointer");
return FAILURE;
}
/*连接redis*/
redisContext *context = redisConnect(REDIS_SERVER_IP,REDIS_SERVER_PORT);
if(context->err)
{
redisFree(context);
printf("%d connect redis server failure:%s\n",__LINE__, context->errstr);
return FAILURE;
}
printf("connect redis server success\n");

/*执行redis命令*/
redisReply *reply = (redisReply *)redisCommand(context, cmd);
if(NULL == reply)
{
printf("%d execute command:%s failure\n",__LINE__,cmd);
redisFree(context);
return FAILURE;
}
//返回执行结果为整型的命令,只有状态为REDIS_REPLY_INTEGER,并且INTEGER是大于0时,才表示这种类型的命令执行成功
if(!(reply->type == REDIS_REPLY_INTEGER && reply->integer > 0))
{
printf("%d execute command:%s failure\n",__LINE__, cmd);
freeReplyObject(reply);
redisFree(context);
return FAILURE;
}

freeReplyObject(reply);
redisFree(context);
printf("%d execute command:%s success\n",__LINE__,cmd);
return SUCCESS;

}
/**************************************
函数名:quryStuBySid
函数功能:通过sid查询学生信息
输入参数:cmd redis命令
输出参数:redis 返回结构
返回值:STU_RESULT
*************************************/
STU_RESULT queryStuBySid(char *sid)
{
char cmd[CMD_MAX_LENGHT] = {0};
/*入参检查*/
if(NULL == sid)
{
printf("%d NULL pointer\n",__LINE__);
return FAILURE;
}
/*组装执行命令*/
snprintf(cmd,CMD_MAX_LENGHT,"HGETALL stu:%s",sid);
if(FAILURE == exeRedisStrCmd(cmd))
{
printf("%d query stu failue",__LINE__);
return FAILURE;
}
return SUCCESS;
}
STU_RESULT exeRedisStrCmd(char *cmd)
{

/*检查入参*/
if(NULL == cmd)
{
printf("NULL pointer");
return FAILURE;
}

/*连接redis*/
redisContext *context = redisConnect(REDIS_SERVER_IP,REDIS_SERVER_PORT);
if(context->err)
{
redisFree(context);
printf("%d connect redis server failure:%s\n",__LINE__, context->errstr);
return FAILURE;
}
printf("connect redis server success\n");

/*执行redis命令*/
redisReply *reply = (redisReply *)redisCommand(context, cmd);
if(NULL == reply)
{
printf("%d execute command:%s failure\n",__LINE__,cmd);
redisFree(context);
return FAILURE;
}
//返回执行结果为整型的命令,只有状态为REDIS_REPLY_INTEGER,并且INTEGER是大于0时,才表示这种类型的命令执行成功
if(!(reply->type == REDIS_REPLY_ARRAY && reply->elements > 0))
{
printf("%d execute command:%s failure\n",__LINE__, cmd);
freeReplyObject(reply);
redisFree(context);
return FAILURE;

}

printf("%d,%lu\n",reply->type,reply->elements);
int i = 0;
for(i=0;i < reply->elements;i++)
{
if(i%2 ==0)
{
printf("%s:",reply->element[i]->str);
}
else
{

printf("%s\n",reply->element[i]->str);
}
}
freeReplyObject(reply);
redisFree(context);
return SUCCESS;
}
int main(int argc,char *argv[])
{
Stu_Info_Struct stu =
{
"01",
"hu",
1,
"CS"
};

addStu(&stu);
queryStuBySid("01");
return 0;
}

编译代码

1
gcc -g stu_manager.c -o stu -lhiredis

可能遇到问题:

1
libhiredis.so.0.10: cannot open shared object file: No such file or directory

/usr/lib/hiredis目录下没有hiredis库,将编译链接好的hiredis库拷贝到/usr/lib/hiredis目录下,并且执行命令重新加载配置:

1
ldconfig

启动redis服务器

1
redis-server

运行

1
./stu

运行结果:

1
2
3
4
5
6
7
8
9
hyb@ubuntu-16:redis# ./stu
connect redis server success
116 execute command:hset stu:01 name hu gender 1 major CS success
add student 01,hu,1,CS success
connect redis server success
2,6
name:hu
gender:1
major:CS

程序首先将学生信息添加到数据库中,然后通过id将其结果查询出来。

总结

本文对hiredis的接口进行了简单的介绍,并通过一个小实例说明了这些接口在c中的使用。

守望 wechat
关注公众号[编程珠玑]获取更多原创技术文章
出入相友,守望相助!