Redis系列(四):数据结构String类型中基本操作命令和源码解析

时间:2022-12-18 10:47:31

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,,,,,,},

Redis系列(四):数据结构String类型中基本操作命令和源码解析

 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);
}

Redis系列(四):数据结构String类型中基本操作命令和源码解析

Redis系列(四):数据结构String类型中基本操作命令和源码解析

 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);
}

Redis系列(四):数据结构String类型中基本操作命令和源码解析

 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);
}

Redis系列(四):数据结构String类型中基本操作命令和源码解析

 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系列(四):数据结构String类型中基本操作命令和源码解析的更多相关文章

  1. Redis系列(五):数据结构List双向链表中基本操作操作命令和源码解析

    1.介绍 List是通过ListNode实现的双向链表. 1.双端:获取某个结点的前驱和后继结点都是O(1) 2.无环:表头的prev指针和表尾的next指针都指向NULL,对链表的访问都是以NULL ...

  2. Redis系列(十二):数据结构SortedSet跳跃表中基本操作命令和源码解析

    1.SkipList Redis的sortedSet数据结构是有序不重复的(索引为唯一的,数据(score)却可以重复), 跳表是redis的一个核心组件,也同时被广泛地运用到了各种缓存地实现当中,它 ...

  3. Redis系列-存储篇string主要操作命令

    Redis系列-存储篇string主要操作命令 通过上两篇的介绍,我们的redis服务器基本跑起来.db都具有最基本的CRUD功能,我们沿着这个脉络,开始学习redis丰富的数据结构之旅,当然先从最简 ...

  4. &lbrack;转&rsqb;C&num; 互操作性入门系列&lpar;四&rpar;:在C&num; 中调用COM组件

    传送门 C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 ...

  5. &ast;&ast;&ast;Redis hash是一个string类型的field和value的映射表&period;它的添加、删除操作都是O&lpar;1&rpar;&lpar;平均&rpar;。hash特别适合用于存储对象

    http://redis.readthedocs.org/en/latest/hash/hset.html HSET HSET key field value   (存一个对象的时候key存) 将哈希 ...

  6. Redis hash 是一个 string 类型的 field 和 value 的映射表&period;它的添加、删除操作都是 O&lpar;1&rpar;(平均)。

    2.3 hashes 类型及操作 Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加.删除操作都是 O(1)(平均).hash 特别适合用于存储对象.相 ...

  7. String类型中 &quot&semi;&equals;&equals;&quot&semi;和&quot&semi;equals&quot&semi;比较的差别

    String类型中 "=="和"equals"比较的差别 先说明一下String类型的变量的创建方式 在创建新的String类型的变量时,首先会在缓冲区查找是否 ...

  8. Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  9. Redis(五):hash&sol;hset&sol;hget 命令源码解析

    Redis作为nosql数据库,kv string型数据的支持是最基础的,但是如果仅有kv的操作,也不至于有redis的成功.(memcache就是个例子) Redis除了string, 还有hash ...

随机推荐

  1. Spring和EJB3的技术对比

    随着EJB3规范以及支持EJB3的Java EE应用服务器的即将发布,全新Java EE体系架构的新战争将拉开帷幕,在过去3年中如火如荼的Spring占据了Java EE应用开发基础平台的大半*,面 ...

  2. WIN8 隐私声明

    隐私权声明 本应用连接网络仅为控制硬件设备,不会收集你的个人信息,也不共享你个个人信息. 应用名称 CrossMedia可视化控制系统(服务器版) 关于本应用 本应仅为控制设备应用,不关注任何配置相关 ...

  3. BZOJ3226&lbrack;Sdoi2008&rsqb;校门外的区间 题解

    题目大意: 有5种运算维护集合S(S初始为空)并最终输出S. 5种运算如下: U T  S∪T I T S∩T D T  S-T C T T-S S T S⊕T 基本集合运算如下: A∪B {x : ...

  4. Java&lowbar;生产者消费者模式

    /* * To change this license header, choose License Headers in Project Properties. * To change this t ...

  5. WEB SSH之Shellinabox

    用起来方便的,参考URL: http://lzw.me/a/shellinabox.html 生成 pem 证书,可以 https 方式启动.pem 证书的格式为公钥加私钥,并以 x509 的格式进行 ...

  6. Oracle随机获取记录

    , )) RANDOMNUM FROM DUAL) B ORDER BY B.RANDOMNUM

  7. Thinking in scala &lpar;5&rpar;----高阶函数&ast;

    高阶函数是函数式编程里面一个非常重要的特色,所谓的高阶函数,就是以其它函数作为参数的函数. 下面以一个小例子演示Scala的高阶函数特性,非常有意思,也非常强大. 首先看这么一个程序: code1: ...

  8. &lbrack;Javascript&rsqb; encodeURIComponent&lpar;&rpar;方法

    在vue項目中使用vue-router通过url进行传值 encodeURIComponent encodeURIComponent() 函数可把字符串作为 URI 组件进行编码.encodeURIC ...

  9. Java基础1:深入理解Java面向对象三大特性

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  10. jmeter手写脚本,使用正则获取cookie(禁用cookies管理器)

    注:这里以bugfree为例 1.bugfree登录时会有重定向,这会导致每个URL都会有.因此要手动获取cookie的时候,需要去掉重定向勾选 正则获取动态PHPsession 获取到值后,放到信息 ...