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 ...
随机推荐
- js生成一个上限跟下限的随机数
function sj() { //x上限,y下限 var x = 2000; var y = 1800; var rand = parseInt(Math.random() * (x - y + 1 ...
- HashMap集合嵌套集合方法四种
Map<String, HashMap<Person, String>> m=new HashMap<String, HashMap<Person, String& ...
- IDEA奇淫小技巧
IDEA是目前市场上最好用的IDE,我说的! 前几年eclipse在市场上非常流行,因此大多数人都习惯了eclipse的一些快捷键.近年来,随着IDEA的兴起,很多人都放弃了exlipse,进而选择了 ...
- vue-cli3的eslint配置问题
vue-cli3按照官网教程配置搭建后,发现每次编译,eslint都抛出错误 error: Expected indentation of 4 spaces but found 0 (indent) ...
- 第二章-数据绑定和第一个AnglarJS Web应用
Angularjs中的数据绑定 AngularJS创建实时模板来代替视图,而不是将数据合并进模板之后更新DOM.任何一个独立视图组件中的值都是动态替换的.这个功能可以说是AngularJS中最最重要的 ...
- C#基础之构造函数(构造器)
在每个类里面默认都有一个构造方法,正式因为有了这些方法,你未赋值的变量才会有初始值,当然,我们也可以手动自己创建构造函数,可以创建多个构造函数,自己给出默认值或者!!!规定调用此类的程序对象必须要赋值 ...
- 七、Spring MVC高级技术
知识点 处理文件上传 使用flash属性 在控制器中处理异常 关键词 控制器通知 (Controller Advice) 7.1 处理异常 Spring提供了多种方式将异常转换为响应: 特定的Spri ...
- Chisel3 - Tutorial - Tbl
https://mp.weixin.qq.com/s/e8vJ8claauBtiuedxYYaJw 实现可以动态索引的表. 参考链接: https://github.com/ucb-bar/c ...
- C#中值类型,引用类型,字符串类型的区别(内存图解)
如果用图片来解释值类型,引用类型和字符串类型(引用类型的一种)的区别的话 值类型: 引用类型: string类型:
- 如何选出适合自己的管理Helm Chart的最佳方式?
本文转载自Rancher Labs 无论你喜欢与否,你都不得不承认Helm是管理Kubernetes应用程序独一无二的工具,你甚至可以通过不同的方式使用它. 在Helm的使用过程中,我们注意到有几个问 ...