目錄
1. 數(shù)據(jù)庫類型
1.1 基本概念
1.2 關(guān)系/非關(guān)系型數(shù)據(jù)庫搭配使用
2. Redis ?
2.1 基本知識(shí)點(diǎn)
2.2 redis常用命令
2.4 redis數(shù)據(jù)持久化
3 hiredis的使用
4. 復(fù)習(xí)
1. 數(shù)據(jù)庫類型
1.1 基本概念
-
關(guān)系型數(shù)據(jù)庫 - sql
-
操作數(shù)據(jù)必須要使用sql語句
-
數(shù)據(jù)存儲(chǔ)在磁盤
-
存儲(chǔ)的數(shù)據(jù)量大
-
舉例:
-
mysql
-
oracle
-
sqlite - 文件數(shù)據(jù)庫
-
sql server
-
-
-
非關(guān)系數(shù)據(jù)庫 - nosql
-
操作不使用sql語句
-
命令
-
-
數(shù)據(jù)默認(rèn)存儲(chǔ)在內(nèi)存
-
速度快, 效率高
-
存儲(chǔ)的數(shù)據(jù)量小
-
-
不需要數(shù)據(jù)庫表
-
以鍵值對(duì)的方式存儲(chǔ)的
-
-
1.2 關(guān)系/非關(guān)系型數(shù)據(jù)庫搭配使用
?
==RDBMS: Relational Database Management System== 關(guān)系型數(shù)據(jù)庫
-
所有的數(shù)據(jù)默認(rèn)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫中
-
客戶端訪問服務(wù)器, 有一些數(shù)據(jù), 服務(wù)器需要頻繁的查詢數(shù)據(jù)
-
服務(wù)器首先將數(shù)據(jù)從關(guān)系型數(shù)據(jù)庫中讀出 -> 第一次
-
將數(shù)據(jù)寫入到redis中
-
-
客戶端第二次包含以后訪問服務(wù)器
-
服務(wù)器從redis中直接讀數(shù)據(jù)
-
-
2. Redis ?
-
知道redis是什么?
-
非關(guān)系型數(shù)據(jù)庫 也可以叫 內(nèi)存數(shù)據(jù)庫
-
-
能干什么?
-
存儲(chǔ)訪問頻率高的數(shù)據(jù)
-
共享內(nèi)存
-
服務(wù)器端 -> redis
-
-
-
怎么使用?
-
常用的操作命令
-
各種數(shù)據(jù)類型 -> 會(huì)查
-
-
redis的配置文件
-
redis的數(shù)據(jù)持久化
-
寫程序的時(shí)候如何對(duì)redis進(jìn)行操作
-
客戶端 -> 服務(wù)器
-
-
2.1 基本知識(shí)點(diǎn)
-
安裝包下載
-
英文官方: Redis
-
中文官方: CRUG網(wǎng)站
-
-
Redis安裝
-
make
-
make install
-
-
redis中的兩個(gè)角色
# 服務(wù)器 - 啟動(dòng)
redis-server # 默認(rèn)啟動(dòng)
redis-server confFileName # 根據(jù)配置文件的設(shè)置啟動(dòng) 遠(yuǎn)程
# 客戶端
redis-cli # 默認(rèn)連接本地, 綁定了6379默認(rèn)端口的服務(wù)器
redis-cli -p 端口號(hào)
redis-cli -h IP地址 -p 端口 # 連接遠(yuǎn)程主機(jī)的指定端口的redis
# 通過客戶端關(guān)閉服務(wù)器
shutdown
# 客戶端的測(cè)試命令
ping [MSG]
redis中數(shù)據(jù)的組織格式
-
鍵值對(duì)
-
key: 必須是字符串 - "hello"
-
value: 可選的
-
String類型
-
List類型
-
Set類型
-
SortedSet類型
-
Hash類型
-
-
redis中常用數(shù)據(jù)類型
-
String類型
-
字符串
-
-
List類型
-
存儲(chǔ)多個(gè)string字符串的
-
-
Set類型
-
集合
-
stl集合
-
默認(rèn)是排序的, 元素不重復(fù)
-
-
redis集合
-
元素不重復(fù), 數(shù)據(jù)是無序的
-
-
-
-
SortedSet類型
-
排序集合, 集合中的每個(gè)元素分為兩部分
-
[分?jǐn)?shù), 成員] -> [66, ''tom'']
-
-
-
Hash類型
-
跟map數(shù)據(jù)組織方式一樣: key:value
-
Qt -> QHash, QMap
-
Map -> 紅黑樹
-
hash -> 數(shù)組
-
a[index] = xx?
-
-
-
2.2 redis常用命令
String類型
key -> string
value -> string
# 設(shè)置一個(gè)鍵值對(duì)->string:string
SET key value
# 通過key得到value
GET key
# 同時(shí)設(shè)置一個(gè)或多個(gè) key-value 對(duì)
MSET key value [key value ...]
# 同時(shí)查看過個(gè)key
MGET key [key ...]
# 如果 key 已經(jīng)存在并且是一個(gè)字符串, APPEND 命令將 value 追加到 key 原來的值的末尾
# key: hello, value: world, append: 12345 world12345
APPEND key value
# 返回 key 所儲(chǔ)存的字符串值的長(zhǎng)度
STRLEN key
# 將 key 中儲(chǔ)存的數(shù)字值減一。
# 前提, value必須是數(shù)字字符串 -"12345"
DECR key
List類型 - 存儲(chǔ)多個(gè)字符串
key -> string
value -> list
# 將一個(gè)或多個(gè)值 value 插入到列表 key 的表頭
LPUSH key value [value ...]
# 將一個(gè)或多個(gè)值 value 插入到列表 key 的表尾 (最右邊)。
RPUSH key value [value ...]
# list中刪除元素
LPOP key # 刪除最左側(cè)元素
RPOP key # 刪除最右側(cè)元素
# 遍歷
LRANGE key start stop
start: 起始位置, 0
stop: 結(jié)束位置, -1
# 通過下標(biāo)得到對(duì)應(yīng)位置的字符串
LINDEX key index
# list中字符串的個(gè)數(shù)
LLEN key
Set類型
key -> string
value -> set類型 ("string", "string1")
# 添加元素
# 將一個(gè)或多個(gè) member 元素加入到集合 key 當(dāng)中,已經(jīng)存在于集合的 member 元素將被忽略
SADD key member [member ...]
# 遍歷
SMEMBERS key
# 差集
SDIFF key [key ...]
# 交集
SINTER key [key ...]
# 并集
SUNION key [key ...]
SortedSet 類型
key -> string
value -> sorted ([socre, member], [socre, member], ...)
# 添加元素
ZADD key score member [[score member] [score member] ...]
# 遍歷
ZRANGE key start stop [WITHSCORES] # -> 升序集合
ZREVRANGE key start stop [WITHSCORES] # -> 降序集合
# 指定分?jǐn)?shù)區(qū)間內(nèi)元素的個(gè)數(shù)
ZCOUNT key min max
Hash類型
?
key ->string
value -> hash ([key:value], [key:value], [key:value], ...)
# 添加數(shù)據(jù)
HSET key field value
# 取數(shù)據(jù)
HGET key field
# 批量插入鍵值對(duì)
HMSET key field value [field value ...]
# 批量取數(shù)據(jù)
HMGET key field [field ...]
# 刪除鍵值對(duì)
HDEL key field [field ...]
Key 相關(guān)的命令
# 刪除鍵值對(duì)
DEL key [key ...]
# 查看key值
KEYS pattern
查找所有符合給定模式 pattern 的 key 。
KEYS * 匹配數(shù)據(jù)庫中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS h*llo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
# 給key設(shè)置生存時(shí)長(zhǎng)
EXPIRE key seconds
# 取消生存時(shí)長(zhǎng)
PERSIST key
# key對(duì)應(yīng)的valued類型
TYPE key
配置文件是給redis服務(wù)器使用 的
-
配置文件位置
-
從源碼安裝目錄中找 -> redis.conf
-
-
配置文件配置項(xiàng)
# redis服務(wù)器綁定誰之后, 誰就能訪問redis服務(wù)器
# 任何客戶端都能訪問服務(wù)器, 需要注釋該選項(xiàng)
bind 127.0.0.1 192.168.1.100
# 保護(hù)模式, 如果要遠(yuǎn)程客戶端訪問服務(wù)器, 該模式要關(guān)閉
protected-mode yes
# reids服務(wù)器啟動(dòng)時(shí)候綁定的端口, 默認(rèn)為6379
port 6379
# 超時(shí)時(shí)長(zhǎng), 0位關(guān)閉該選項(xiàng), >0則開啟
timeout 0
# 服務(wù)器啟動(dòng)之后不是守護(hù)進(jìn)程 一般會(huì)使用yes 讓其為守護(hù)進(jìn)程
daemonize yes
# 如果服務(wù)器是守護(hù)進(jìn)程, 就會(huì)生成一個(gè)pid文件
# ./ -> reids服務(wù)器啟動(dòng)時(shí)候?qū)?yīng)的目錄
pidfile ./redis.pid
# 日志級(jí)別
loglevel notice
# 如果服務(wù)器是守護(hù)進(jìn)程, 才會(huì)寫日志文件
logfile "" -> 這是沒寫
logfile "./redis.log" //打印的是終端的信息
# redis中數(shù)據(jù)庫的個(gè)數(shù) 默認(rèn)是16個(gè) 類似于mysql中的database
databases 16
- 切換 select dbID [dbID == 0 ~ 16-1]
2.4 redis數(shù)據(jù)持久化
持久化: 數(shù)據(jù)從內(nèi)存到磁盤的過程 關(guān)機(jī)之后內(nèi)存的數(shù)據(jù)釋放了 但是存在磁盤上 下次可以直接讀取磁盤的數(shù)據(jù)
持久化的兩種方式: rgb和aof兩種方式
rgb數(shù)據(jù)完整性較低 但效率高 aof數(shù)據(jù)完整性高 但效率低
-
rdb方式
-
這是一種默認(rèn)的持久化方式, 默認(rèn)打開
-
磁盤的持久化文件xxx.rdb
-
將內(nèi)存數(shù)據(jù)以二進(jìn)制的方式直接寫入磁盤文件
-
文件比較小, 恢復(fù)時(shí)間短, 效率高
-
以用戶設(shè)定的頻率 -> 容易丟失數(shù)據(jù)
-
數(shù)據(jù)完整性相對(duì)較低
-
-
aof方式
-
默認(rèn)是關(guān)閉的
-
磁盤的持久化文件xxx.aof
-
直接將生成數(shù)據(jù)的命令寫入磁盤文件
-
文件比較大, 恢復(fù)時(shí)間長(zhǎng), 效率低
-
以某種頻率 -> 1sec
-
數(shù)據(jù)完整性高
-
# rdb的同步頻率, 任意一個(gè)滿足都可以
save 900 1 //900s發(fā)生1次改變
save 300 10 //300發(fā)生10次改變
save 60 10000
# rdb文件的名字
dbfilename dump.rdb
# 生成的持久化文件保存的那個(gè)目錄下, rdb和aof
dir ./
# 是不是要打開aof模式
appendonly no
-> 打開: yes
# 設(shè)置aof文件的名字
appendfilename "appendonly.aof"
# aof更新的頻率
# appendfsync always
appendfsync everysec
# appendfsync no
-
aof和rdb能不能同時(shí)打開?
-
可以
-
-
aof和rdb能不能同時(shí)關(guān)閉?
-
可以
-
rdb如何關(guān)閉?
save ""
-
-
兩種模式同時(shí)開啟, 如果要進(jìn)行數(shù)據(jù)恢復(fù), 如何選擇?
-
效率上考慮: rdb模式
-
數(shù)據(jù)的完整性: aof模式
-
3 hiredis的使用
-
hiredis的安裝
-
下載地址: Redis客戶端連接工具資料 -- Redis中文網(wǎng) -- Redis中國用戶組(CRUG)
-
安裝
-
make
-
make
-
-
-
hiredis API接口的使用
連接數(shù)據(jù)庫
// 連接數(shù)據(jù)庫
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip,
int port, const struct timeval tv);
執(zhí)行redis命令函數(shù)
// 執(zhí)行redis命令
void *redisCommand(redisContext *c, const char *format, ...);
//雖然返回的是void *實(shí)際上是redisply類型
// redisCommand 函數(shù)實(shí)際的返回值類型
typedef struct redisReply {
/* 命令執(zhí)行結(jié)果的返回類型 */
int type;
/* 存儲(chǔ)執(zhí)行結(jié)果返回為整數(shù) */
long long integer;
/* str變量的字符串值長(zhǎng)度 */
size_t len;
/* 存儲(chǔ)命令執(zhí)行結(jié)果返回是字符串, 或者錯(cuò)誤信息 */
char *str;
/* 返回結(jié)果是數(shù)組, 代表數(shù)據(jù)的大小 */
size_t elements;
/* 存儲(chǔ)執(zhí)行結(jié)果返回是數(shù)組*/
struct redisReply **element;
} redisReply;
//訪問數(shù)組里面的元素
redisReply a[100];
element[i]->str
//根據(jù)類型取出對(duì)應(yīng)的值
type為類型
type狀態(tài)表示 | 含義 |
---|---|
REDIS_REPLY_STRING==1 | 返回值是字符串,字符串儲(chǔ)存在redis->str當(dāng)中,字符串長(zhǎng)度為redi |
REDIS_REPLY_ARRAY== 2 | 返回值是數(shù)組,數(shù)組大小存在redis->elements里面,數(shù)組值存儲(chǔ)在redis->element[i]里面。數(shù)組里面存儲(chǔ)的是指向redisReply的指針,數(shù)組里面的返回值可以通過redis->element[i]->str來訪問,數(shù)組的結(jié)果里全是type==REDIS_REPLY_STRING的redisReply對(duì)象指針。 |
REDIS_REPLY_INTEGER == 3 | 返回整數(shù)long long,從integer字段獲取值 |
REDIS_REPLY_NIL==4 | 返回值為空表示執(zhí)行結(jié)果為空 |
REDIS_REPLY_STATUS ==5 | 返回命令執(zhí)行的狀態(tài),比如set foo bar 返回的狀態(tài)為OK,存儲(chǔ)在str當(dāng)中 reply->str == "OK" 。 |
REDIS_REPLY_ERROR ==6 | 命令執(zhí)行錯(cuò)誤,錯(cuò)誤信息存放在 reply->str當(dāng)中。 |
?釋放資源
// 釋放資源
void freeReplyObject(void *reply);
void redisFree(redisContext *c);
案列代碼
#include <stdio.h>
#include <hiredis.h>
int main()
{
// 1. 連接redis服務(wù)器
redisContext* c = redisConnect("127.0.0.1", 6379);
if (c->err != 0)
{
return -1;
}
// 2. 執(zhí)行redis命令
void *prt = redisCommand(c, "hmset user userName zhang3 passwd 123456 age 23 sex man");
redisReply* ply = (redisReply*)prt;
if(ply->type == 5)
{
// 狀態(tài)輸出
printf("狀態(tài): %s\n", ply->str);
}
freeReplyObject(ply);
// 3. 從數(shù)據(jù)庫中讀數(shù)據(jù)
prt = redisCommand(c, "hgetall user");
ply = (redisReply*)prt;
if(ply->type == 2)
{
// 遍歷
for(int i=0; i<ply->elements; i+=2)
{
printf("key: %s, value: %s\n", ply->element[i]->str, ply->element[i+1]->str);
}
}
freeReplyObject(ply);
redisFree(c);
return 0;
}
4. 復(fù)習(xí)
fastDFS
-
是什么?
-
分布式文件系統(tǒng)
-
-
干什么?
-
提供文件上傳
-
提供文件下載
-
-
怎么使用?
-
根據(jù)主機(jī)的角色 -> 修改對(duì)應(yīng)的配置文件
-
啟動(dòng)各個(gè)角色
-
fdfs_trackerd /etc/fdfs/tracker.conf
fdfs_storaged /etc/fdfs/storage.conf
客戶端編寫

- 操作步驟
1. 創(chuàng)建管道 - pipe
2. 創(chuàng)建子進(jìn)程
3. 子進(jìn)程干什么?
- 寫管道, 關(guān)閉讀端
- 將標(biāo)準(zhǔn)輸出 -> 管道的寫端
- 重定向
- 執(zhí)行execl命令, 調(diào)用另外的進(jìn)程fdfs_upload_file
- 子進(jìn)程退出
4. 父進(jìn)程?
- 讀管道, 關(guān)閉寫端
- 釋放子進(jìn)程資源 - pcb
- wait()/ waitpid()
實(shí)現(xiàn)代碼
fdfs.upload_file.h
#ifdef _FDFS_UPLOAD_FILE_H
#define _FDFS_UPLOAD_FILE_H
int upload_file1(const char *configfile, const char * myfile,char * fileid);
int upload_file2(const char * configFile, const char * upLoadFile, char * fileid, int size);
#endif
fdfs.upload_file.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "fdfs_client.h"
#include "fdfs_upload_file.h"
//第一種方法 改寫源碼 將其改為底層可用
int upload_file1(const char *configfile, const char * myfile,char * fileid)
{
char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
ConnectionInfo *pTrackerServer;
int result;
int store_path_index;
ConnectionInfo storageServer;
if ((result=fdfs_client_init(configfile)) != 0)
{
return result;
}
pTrackerServer = tracker_get_connection();
if (pTrackerServer == NULL)
{
fdfs_client_destroy();
return errno != 0 ? errno : ECONNREFUSED;
}
*group_name = '\0';
if ((result=tracker_query_storage_store(pTrackerServer, \
&storageServer, group_name, &store_path_index)) != 0)
{
fdfs_client_destroy();
fprintf(stderr, "tracker_query_storage fail, " \
"error no: %d, error info: %s\n", \
result, STRERROR(result));
return result;
}
result = storage_upload_by_filename1(pTrackerServer, \
&storageServer, store_path_index, \
myfile, NULL, \
NULL, 0, group_name, fileid);
if (result == 0)
{
printf("%s\n", fileid);
}
else
{
fprintf(stderr, "upload file fail, " \
"error no: %d, error info: %s\n", \
result, STRERROR(result));
}
tracker_disconnect_server_ex(pTrackerServer, true);
fdfs_client_destroy();
return result;
}
//第二種方法 使用execlp
//使用多進(jìn)程實(shí)現(xiàn)
int upload_file2(const char * configFile, const char * upLoadFile, char * fileid, int size)
{
//1、創(chuàng)建管道
int fd[2];
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe error");
return -1;
}
//2、創(chuàng)建子線程
pid_t pid = fork();
//如果是子線程
if(pid == 0)
{
//3、重定向到管道的寫端 old,new
dup2(fd[1], STDIN_FILENO);
//關(guān)閉讀端
close(fd[0]);
//執(zhí)行exclp命令
execlp("file_upload_file", "xxx", configFile, upLoadFile, NULL);
perror("execlp error");
}
else
{
//關(guān)閉寫端
close(fd[1]);
//讀取數(shù)據(jù) 將數(shù)據(jù)讀出到fileid參數(shù)中
char buf[1024];
read(fd[0], fileid, size);
//回收子進(jìn)程
wait(NULL);
}
}
main.c文章來源:http://www.zghlxwxcb.cn/news/detail-490564.html
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdfs_upload_file.h"
//查找位置 在編譯時(shí)加上
//find / -name "fdfs_client.h"
int main(int argc, char **argv[])
{
char fileID[1024];
upload_file1("/etc/fdfs/client.conf", "main.c", fileID);
printf("fileID: %s\n", fileID);
printf("================================================================\n");
upload_file2("/etc/fdfs/client.conf", "main.c", fileID, sizeof(fileID));
printf("fileID: %s\n", fileID);
return 0;
};
執(zhí)行 需要找到頭文件和庫文章來源地址http://www.zghlxwxcb.cn/news/detail-490564.html
gcc *.c -I /usr/include/fastdfs -I /usr/include/fastcommon/ -lfdfsclient
到了這里,關(guān)于分布式學(xué)習(xí)第二天 redis學(xué)習(xí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!