Redis系列(四):数据结构String类型中基本操作命令和源码解析
1.介绍
string类型本质上是char[]数组的封装
中文网:http://www.redis.cn/commands.html#string
2.常用命令
set 命令
set命令的时间复杂度是O(1)
将键key设定为指定的“字符串”值。
如果 key 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。
当set命令执行成功之后,之前设置的过期时间都将失效
SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds – 设置键key的过期时间,单位时秒
PX milliseconds – 设置键key的过期时间,单位时毫秒
NX – 只有键key不存在的时候才会设置key的值
XX – 只有键key存在的时候才会设置key的值
127.0.0.1:> set myKey "Hello"
OK
127.0.0.1:> get myKey
"Hello"
127.0.0.1:> set userId ""
OK
127.0.0.1:> get userId
""
127.0.0.1:> object encoding userId
"int"
127.0.0.1:> object encoding myKey
"embstr"
127.0.0.1:> set myKey World NX
(nil)
127.0.0.1:> set myKey World XX
OK
127.0.0.1:>
NX :应用场景分布式锁:通过myKey的赋值来判断是否获取到了一个分布式锁 如果OK说明获取到了锁 如果nil说明没有获取到了锁
如果存放到string中的value是int,那么在内部还是int ,可以从encoding
redisObject中有一个type属性和encoding属性
incr/incrby/decr/decrby命令
incr/decr 自增或者自减1
incrby/decrby:自增或者自减指定数
127.0.0.1:> INCR userId
(integer)
127.0.0.1:> INCR userId
(integer)
127.0.0.1:> get userId
""
127.0.0.1:> INCRBY userId
(integer)
127.0.0.1:> DECR userId
(integer)
127.0.0.1:> DECRBY userId
(integer)
append命令
127.0.0.1:> APPEND myKey "!"
(integer)
127.0.0.1:> get myKey
"World!"
127.0.0.1:>
3.源码解析
redisCommand存放着所有的命令
{"set",setCommand,-,
"write use-memory @string",
,NULL,,,,,,},

setCommand源码
setCommand传入一个client结构体
最后调用setGenericCommand函数来处理set
/* SET key value [NX] [XX] [KEEPTTL] [EX <seconds>] [PX <milliseconds>] */
void setCommand(client *c) {
int j;
robj *expire = NULL;
int unit = UNIT_SECONDS;
int flags = OBJ_SET_NO_FLAGS; for (j = ; j < c->argc; j++) {
char *a = c->argv[j]->ptr;
robj *next = (j == c->argc-) ? NULL : c->argv[j+]; if ((a[] == 'n' || a[] == 'N') &&
(a[] == 'x' || a[] == 'X') && a[] == '\0' &&
!(flags & OBJ_SET_XX))
{
flags |= OBJ_SET_NX;
} else if ((a[] == 'x' || a[] == 'X') &&
(a[] == 'x' || a[] == 'X') && a[] == '\0' &&
!(flags & OBJ_SET_NX))
{
flags |= OBJ_SET_XX;
} else if (!strcasecmp(c->argv[j]->ptr,"KEEPTTL") &&
!(flags & OBJ_SET_EX) && !(flags & OBJ_SET_PX))
{
flags |= OBJ_SET_KEEPTTL;
} else if ((a[] == 'e' || a[] == 'E') &&
(a[] == 'x' || a[] == 'X') && a[] == '\0' &&
!(flags & OBJ_SET_KEEPTTL) &&
!(flags & OBJ_SET_PX) && next)
{
flags |= OBJ_SET_EX;
unit = UNIT_SECONDS;
expire = next;
j++;
} else if ((a[] == 'p' || a[] == 'P') &&
(a[] == 'x' || a[] == 'X') && a[] == '\0' &&
!(flags & OBJ_SET_KEEPTTL) &&
!(flags & OBJ_SET_EX) && next)
{
flags |= OBJ_SET_PX;
unit = UNIT_MILLISECONDS;
expire = next;
j++;
} else {
addReply(c,shared.syntaxerr);
return;
}
} c->argv[] = tryObjectEncoding(c->argv[]);
setGenericCommand(c,flags,c->argv[],c->argv[],expire,unit,NULL,NULL);
}


setGenericCommand源码
可以看出调用了genericSetKey函数
void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) {
long long milliseconds = ; /* initialized to avoid any harmness warning */
if (expire) {
if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != C_OK)
return;
if (milliseconds <= ) {
addReplyErrorFormat(c,"invalid expire time in %s",c->cmd->name);
return;
}
if (unit == UNIT_SECONDS) milliseconds *= ;
}
if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||
(flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL))
{
addReply(c, abort_reply ? abort_reply : shared.null[c->resp]);
return;
}
genericSetKey(c,c->db,key,val,flags & OBJ_SET_KEEPTTL,);
server.dirty++;
if (expire) setExpire(c,c->db,key,mstime()+milliseconds);
notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id);
if (expire) notifyKeyspaceEvent(NOTIFY_GENERIC,
"expire",key,c->db->id);
addReply(c, ok_reply ? ok_reply : shared.ok);
}

genericSetKey源码
void genericSetKey(client *c, redisDb *db, robj *key, robj *val, int keepttl, int signal) {
if (lookupKeyWrite(db,key) == NULL) {
dbAdd(db,key,val);
} else {
dbOverwrite(db,key,val);
}
incrRefCount(val);
if (!keepttl) removeExpire(db,key);
if (signal) signalModifiedKey(c,db,key);
}

dbOverwrite源码
可以看出最后存入dict中
void dbOverwrite(redisDb *db, robj *key, robj *val) {
dictEntry *de = dictFind(db->dict,key->ptr);
serverAssertWithInfo(NULL,key,de != NULL);
dictEntry auxentry = *de;
robj *old = dictGetVal(de);
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
val->lru = old->lru;
}
dictSetVal(db->dict, de, val);
if (server.lazyfree_lazy_server_del) {
freeObjAsync(old);
dictSetVal(db->dict, &auxentry, NULL);
}
dictFreeVal(db->dict, &auxentry);
}

Redis系列(四):数据结构String类型中基本操作命令和源码解析的更多相关文章
- Redis系列(五):数据结构List双向链表中基本操作操作命令和源码解析
1.介绍 List是通过ListNode实现的双向链表. 1.双端:获取某个结点的前驱和后继结点都是O(1) 2.无环:表头的prev指针和表尾的next指针都指向NULL,对链表的访问都是以NULL ...
- Redis系列(十二):数据结构SortedSet跳跃表中基本操作命令和源码解析
1.SkipList Redis的sortedSet数据结构是有序不重复的(索引为唯一的,数据(score)却可以重复), 跳表是redis的一个核心组件,也同时被广泛地运用到了各种缓存地实现当中,它 ...
- Redis系列-存储篇string主要操作命令
Redis系列-存储篇string主要操作命令 通过上两篇的介绍,我们的redis服务器基本跑起来.db都具有最基本的CRUD功能,我们沿着这个脉络,开始学习redis丰富的数据结构之旅,当然先从最简 ...
- [转]C# 互操作性入门系列(四):在C# 中调用COM组件
传送门 C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 ...
- ***Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。hash特别适合用于存储对象
http://redis.readthedocs.org/en/latest/hash/hset.html HSET HSET key field value (存一个对象的时候key存) 将哈希 ...
- Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加、删除操作都是 O(1)(平均)。
2.3 hashes 类型及操作 Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加.删除操作都是 O(1)(平均).hash 特别适合用于存储对象.相 ...
- String类型中 "=="和"equals"比较的差别
String类型中 "=="和"equals"比较的差别 先说明一下String类型的变量的创建方式 在创建新的String类型的变量时,首先会在缓冲区查找是否 ...
- Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Redis(五):hash/hset/hget 命令源码解析
Redis作为nosql数据库,kv string型数据的支持是最基础的,但是如果仅有kv的操作,也不至于有redis的成功.(memcache就是个例子) Redis除了string, 还有hash ...
随机推荐
- java链接redis
创建maven项目 2.导入jar包 <dependencies> <dependency> <groupId>redis.clients</groupId& ...
- Kubernetes实战 - 从零开始搭建微服务 - 1.5 提高可用性-发布多节点的Node/Express网络应用程序
1.5 提高可用性-发布多节点的Node/Express网络应用程序 Kubernetes实战 - 从零开始搭建微服务 前言 在上一篇文章中,已经学习了如何简单地开发一个单层网络应用.[Kuberne ...
- 小智的旅行(Bridge)51nod 提高组试题
luogu AC传送门(官方数据) 题目描述 小智最喜欢旅行了,这次,小智来到了一个岛屿众多的地方,有N座岛屿,编号为0到N-1,岛屿之间 由一些桥连接,可以从桥的任意一端到另一端,由于岛屿可能比较大 ...
- 题解 P4071 【[SDOI2016]排列计数】 (费马小定理求组合数 + 错排问题)
luogu题目传送门! luogu博客通道! 这题要用到错排,先理解一下什么是错排: 问题:有一个数集A,里面有n个元素 a[i].求,如果将其打乱,有多少种方法使得所有第原来的i个数a[i]不在原来 ...
- html5学习之路_007
CSS概述 CSS指层叠样式表 CSS样式表极大地提高了工作效率 CSS基础语法 selector { property:value } 例:hi {color:red; font-size:14px ...
- html5学习之路_003
html布局 使用<div>元素布局 使用<table>元素布局 <div>元素布局 <!DOCTYPE html> <html> < ...
- [Objective-C] 014_Objective-C 代码规范指南
本文参考引用(http://www.csdn.net/article/2015-06-01/2824818-objective-c-style-guide/1) 拥有良好的编码规范,能使我们的代码保持 ...
- Python中出现 SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 12-13: truncated \UXXXXXXXX escape
Python中出现 SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 12-13: t ...
- (九)显示交易记录 &解决相对路径问题
UserServlet.java package com.aff.bookstore.servlet; import java.io.IOException; import javax.servlet ...
- Object类及其equals()方法
== : 1.基本数据类型:根据基本数据类型的值判断是否相等,相等返回true,反之返回false 注意:两端数据类型可以不同, 在不同的情况下,也可以返回true 2.引用数据类型:Object ...