Redis构建了自己的类型系统,主要包括
C语言不是面向对象语言,这里将redisObject称呼为对象是为了讲述方便,让里面的内容更容易被理解,redisObject其实是一个结构体。
Redis内部使用一个redisObject对象来表示所有的key和value,每次在Redis数据块中创建一个键值对时,一个是键对象,一个是值对象,而Redis中的每个对象都是由redisObject结构来表示。
在Redis中,键总是一个字符串对象,而值可以是字符串、列表、集合等对象,所以我们通常说键为字符串键,表示这个键对应的值为字符串对象,我们说一个键为集合键时,表示这个键对应的值为集合对象
redisobject最主要的信息:
redisobject源码
typedef struct redisObject{
//类型
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层数据结构的指针
void *ptr;
//引用计数
int refcount;
//记录最后一次被程序访问的时间
unsigned lru:22;
}robj
SADD
和 SRANDMEMBER
只能用于集合键。TTL
。当执行一个处理数据类型的命令时,Redis执行以下步骤:
key
,在数据库字典中查找和它相对应的 redisObject
,如果没找到,就返回 NULL
。redisObject
的 type
属性和执行命令所需的类型是否相符,如果不相符,返回类型错误。redisObject
的 encoding
属性所指定的编码,选择合适的操作函数来处理底层的数据结构。小插曲:
更多阿里、腾讯、美团、京东等一线互联网大厂Java面试真题;包含:基础、并发、锁、JVM、设计模式、数据结构、反射/IO、数据库、Redis、Spring、消息队列、分布式、Zookeeper、Dubbo、Mybatis、Maven、面经等。
更多Java程序员技术进阶小技巧;例如高效学习(如何学习和阅读代码、面对枯燥和量大的知识)高效沟通(沟通方式及技巧、沟通技术)
更多Java大牛分享的一些职业生涯分享文档
请点击这里添加》》》》》》》》》社群,免费获取
比你优秀的对手在学习,你的仇人在磨刀,你的闺蜜在减肥,隔壁老王在练腰, 我们必须不断学习,否则我们将被学习者超越!
趁年轻,使劲拼,给未来的自己一个交代!
string 是最常用的一种数据类型,普通的key/value存储都可以归结为string类型,value不仅是string,也可以是数字。其他几种数据类型的构成元素也都是字符串,注意Redis规定字符串的长度不能超过512M
编码字符串对象的编码可以是int
、raw
、embstr
int用来保存整数值,raw用来保存长字符串,embstr用来保存短字符串。embstr编码是用来专门保存短字符串的一种优化编码。
Redis中对于浮点型也是作为字符串保存的,在需要时再将其转换成浮点数类型
编码的转换
常用命令
127.0.0.1:6379> mset user1:name redis user1:age 22
OK
127.0.0.1:6379> mget user1:name user1:age
1) "redis"
2) "22"
incr && incrby<原子操作>
decr && decrby<原子操作>
setnx <小小体验一把分布式锁,真香>
setex
setrange/getrange
其他命令
应用场景
编码
127.0.0.1:6379> lpush list1 hello
(integer) 1
127.0.0.1:637 9> lpush list1 world
(integer) 2
127.0.0.1:6379> lrange list1 0 -1
1) "world"
2) "hello"
127.0.0.1:6379> rpush list2 world
(integer) 1
127.0.0.1:6379> rpush list2 hello
(integer) 2
127.0.0.1:6379> lrange list2 0 -1
1) "world"
2) "hello"
127.0.0.1:6379> lrange list1 0 -1
1) "world"
2) "hello"
127.0.0.1:6379> lpop list1
"world"
127.0.0.1:6379> lrange list1 0 -1
1) "hello"
127.0.0.1:6379> lrange list2 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> rpop list2
"world"
127.0.0.1:6379> lrange list2 0 -1
1) "hello"
rpoplpush
: 第一步从尾部删除元素,第二步从首部插入元素 结合着使用linsert
:插入方法 linsert listname before [集合的元素] [插入的元素]127.0.0.1:6379> lpush list3 hello
(integer) 1
127.0.0.1:6379> lpush list3 world
(integer) 2
127.0.0.1:6379> linsert list3 before hello start
(integer) 3
127.0.0.1:6379> lrange list3 0 -1
1) "world"
2) "start"
3) "hello"
127.0.0.1:6379> lrange list1 0 -1
1) "a"
2) "b"
127.0.0.1:6379> lset list1 0 v
OK
127.0.0.1:6379> lrange list1 0 -1
1) "v"
2) "b"
127.0.0.1:6379> lrange list1 0 -1
1) "b"
2) "b"
3) "a"
4) "b"
127.0.0.1:6379> lrange list1 0 -1
1) "a"
2) "b"
实现数据结构
应用场景
集合对象set是string类型(整数也会转成string类型进行存储)的无序集合。注意集合和列表的区别:集合中的元素是无序的,因此不能通过索引来操作元素;集合中的元素不能有重复。
编码
常用命令
127.0.0.1:6379> sadd set1 aaa
(integer) 1
127.0.0.1:6379> sadd set1 bbb
(integer) 1
127.0.0.1:6379> sadd set1 ccc
(integer) 1
127.0.0.1:6379> smembers set1
1) "aaa"
2) "ccc"
3) "bbb"
127.0.0.1:6379> smembers set1
1) "ccc"
2) "bbb"
127.0.0.1:6379> smembers set2
1) "fff"
2) "rrr"
3) "bbb"
127.0.0.1:6379> sdiff set1 set2
1) "ccc"
127.0.0.1:6379> sdiff set2 set1
1) "fff"
2) "rrr"
127.0.0.1:6379> sinterstore set3 set1 set2
(integer) 1
127.0.0.1:6379> smembers set3
1) "bbb"
127.0.0.1:6379> srandmember set1 1
1) "bbb"
127.0.0.1:6379> srandmember set1 2
1) "ccc"
2) "bbb"
应用场景
和集合对象相比,有序集合对象是有序的。与列表使用索引下表作为排序依据不同,有序集合为每一个元素设置一个分数(score)作为排序依据。
编码
typedef struct zset{
//跳跃表
zskiplist *zsl;
//字典
dict *dice;
}
zset
字典的键保存元素的值,字典的值保存元素的分值,跳跃表节点的object属性保存元素的成员,跳跃表节点的score属性保存元素的分值。这两种数据结构会通过指针来共享相同元素的成员和分值,所以不会产生重复成员和分值,造成内存的浪费。
常用命令
127.0.0.1:6379> zrange zset 0 -1
1) "one"
2) "three"
3) "two"
4) "four"
5) "five"
6) "six"
127.0.0.1:6379> zcard zset
(integer) 6
127.0.0.1:6379> zcount zset 1 4
(integer) 4
127.0.0.1:6379> zrangebyscore zset 0 4 withscores
1) "one"
2) "1"
3) "three"
4) "2"
5) "two"
6) "2"
7) "four"
8) "4"
127.0.0.1:6379> zrange zset 0 -1
1) "one"
2) "three"
3) "two"
4) "four"
5) "five"
6) "six"
127.0.0.1:6379> zremrangebyrank zset 1 3
(integer) 3
127.0.0.1:6379> zrange zset 0 -1
1) "one"
2) "five"
3) "six"
127.0.0.1:6379> zrange zset 0 -1 withscores
1) "one"
2) "1"
3) "five"
4) "5"
5) "six"
6) "6"
127.0.0.1:6379> zremrangebyscore zset 3 6
(integer) 2
127.0.0.1:6379> zrange zset 0 -1 withscores
1) "one"
2) "1"
应用场景
hash对象的键是一个字符串类型,值是一个键值对集合
编码
127.0.0.1:6379> hset user id 1
(integer) 1
127.0.0.1:6379> hset user name z3
(integer) 1
127.0.0.1:6379> hset user add shanxi
(integer) 1
127.0.0.1:6379> hget user id "1"
127.0.0.1:6379> hget user name "z3"
127.0.0.1:6379> hget user add "shanxi"
127.0.0.1:6379> hmset user id 1 name z3 add shanxi
OK
127.0.0.1:6379> hmget user id name add
1) "1"
2) "z3"
3) "shanxi"
127.0.0.1:6379> hincrby user2 id 3
(integer) 6
127.0.0.1:6379> hget user2 id
"6"
127.0.0.1:6379> hget user2 id
"6"
127.0.0.1:6379> hmset user3 id 3 name w5
OK
127.0.0.1:6379> hlen user3
(integer) 2
127.0.0.1:6379> hgetall user3
1) "id"
2) "3"
3) "name"
4) "w3"
5) "add"
6) "beijing"
优点
缺点
应用场景
小插曲:
更多阿里、腾讯、美团、京东等一线互联网大厂Java面试真题;包含:基础、并发、锁、JVM、设计模式、数据结构、反射/IO、数据库、Redis、Spring、消息队列、分布式、Zookeeper、Dubbo、Mybatis、Maven、面经等。
更多Java程序员技术进阶小技巧;例如高效学习(如何学习和阅读代码、面对枯燥和量大的知识)高效沟通(沟通方式及技巧、沟通技术)
更多Java大牛分享的一些职业生涯分享文档
请点击这里添加》》》》》》》》》社群,免费获取
比你优秀的对手在学习,你的仇人在磨刀,你的闺蜜在减肥,隔壁老王在练腰, 我们必须不断学习,否则我们将被学习者超越!
趁年轻,使劲拼,给未来的自己一个交代!
typedef struct redisObject{
//类型
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层数据结构的指针
void *ptr;
//引用计数
int refcount;
//记录最后一次被程序访问的时间
unsigned lru:22;
}robj
内存回收:因为c语言不具备自动内存回收功能,当将redisObject对象作为数据库的键或值而不是作为参数存储时其生命周期是非常长的,为了解决这个问题,Redis自己构建了一个内存回收机制,通过redisobject结构中的refcount实现.这个属性会随着对象的使用状态而不断变化。
内存共享:refcount属性除了能实现内存回收以外,还能实现内存共享
参考资料:《Java中高级核心知识全面解析》限量100份,有一些人已经通过我之前的文章获取了哦!
名额有限先到先得!!!
有想要获取这份学习资料的同学可以点击这里免费获取》》》》》》》