Redis对象

对象结构
redisObject结构:

typedef struct redisObject {
    //类型
    unsigned type:4;
    unsigned notused:2; 
    //编码
    unsigned encoding:4;
    unsigned lru:22; 
    //引用计数
    int refcount;
    //指向底层实现数据结构的指针
    void *ptr;
} robj;

类型
对象的type属性记录了对象的类型,这个属性的值可以是表1-1列出对的常量中的一个

类型常量对象的名称
REDIS_STRING字符串对象
REDIS_LIST列表对象
REDIS_HASH哈希对象
REDIS_SET集合对象
REDIS_ZSET有序集合对象
					表1-1   对象的类型

对于Redis数据库保存的键值对来说,键总是一个字符串对象,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种,因此:

  • 当我们称呼一个数据库键为“字符串键”时,我们指的是“这个数据库键所对应的值为字符串对象”
  • 当我们称呼一个数据库键为“列表键”时,我们指的是“这个数据库键所对应的值为列表对象”

TYPE命令的实现方式也与此类似,当我们对一个数据库键执行TYPE命令时,命令返回的结果为数据库键对应的值对象类型,而不是键对象类型:

# 键为字符串对象,值为字符串对象
127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> TYPE msg
string
# 键为字符串对象,值为列表对象
127.0.0.1:6379> RPUSH numbers 1 3 5
(integer) 3
127.0.0.1:6379> TYPE numbers
list
# 键为字符串对象,值为哈希对象
127.0.0.1:6379> HMSET profile name Tome age 25 career Programmer
OK
127.0.0.1:6379> TYPE profile
hash
# 键为字符串对象,值为集合对象
127.0.0.1:6379> SADD fruits apple banana cherry
(integer) 3
127.0.0.1:6379> TYPE fruits
set
# 键为字符串对象,值为有序集合对象
127.0.0.1:6379> ZADD price 8.5 apple 5.0 banana 6.0 cherry
(integer) 3
127.0.0.1:6379> TYPE price
zset

表1-2列出了TYPE命令在面对不同类型的值对象时所产生的输出
对象 对象type属性的值 TYPE命令的输出

对象对象type属性的值TYPE命令的输出
字符串对象REDIS_STRINGstring
列表对象REDIS_LISTlist
哈希对象REDIS_HASHhash
集合对象REDIS_SETset
有序集合对象REDIS_ZSETzset
			表1-2   不同类型值对象的TYPE命令输出

编码和底层实现
对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。encoding属性记录了对象使用的编码,也即是说这个对象使用了什么数据结构作为对象的底层实现,这个属性的值可以是表1-3列出的常量的其中一个

编码常量编码所对应的底层数据结构
REDIS_ENCODING_INTlong类型的整数
REDIS_ENCODING_EMBSTRembstr编码的简单动态字符串
REDIS_ENCODING_RAW简单动态字符串
REDIS_ENCODING_HT字典
REDIS_ENCODING_LINKEDLIST双端链表
REDIS_ENCODING_ZIPLIST压缩列表
REDIS_ENCODING_INTSET整数集合
REDIS_ENCODING_SKIPLIST跳跃表和字典
					表1-3   对象的编码

每种类型的对象都至少使用了两种不同的编码,表1-4列出了每种类型的对象可以使用的编码

类型编码对象
REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象
REDIS_STRINGREDIS_ENCODING_EMBSTR使用embstr编码的简单动态字符串实现的字符串对象
REDIS_STRINGREDIS_ENCODING_RAW使用简单动态字符串实现的字符串对象
REDIS_LISTREDIS_ENCODING_ZIPLIST使用压缩列表实现的列表对象
REDIS_LISTREDIS_ENCODING_LINKEDLIST使用双端链表实现的列表对象
REDIS_HASHREDIS_ENCODING_ZIPLIST使用压缩列表实现的哈希对象
REDIS_HASHREDIS_ENCODING_HT使用字典实现的哈希对象
REDIS_SETREDIS_ENCODING_INTSET使用整数集合实现的集合对象
REDIS_SETREDIS_ENCODING_HT使用字典实现的集合对象
REDIS_ZSETREDIS_ENCODING_ZIPLIST使用压缩列表实现的有序集合对象
REDIS_ZSETREDIS_ENCODING_SKIPLIST使用跳跃表和字典实现的有序集合对象
					表1-4   不同类型和编码的对象

使用OBJECT ENCODING命令可以查看一个数据库键的值对象的编码:

127.0.0.1:6379> SET msg "hello wrold"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"
127.0.0.1:6379> SADD numbers 1 3 5
(integer) 3
127.0.0.1:6379> OBJECT ENCODING numbers
"intset"
127.0.0.1:6379> SADD numbers "seven"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING numbers
"hashtable"

表1-5列出了不同编码的对象所对应的OBJECT ENCODING命令输出:

对象所使用的底层数据结构编码常量OBJECT ENCODING命令输出
整数REDIS_ENCODING_INTint
embstr编码的简单动态字符串(SDS)REDIS_ENCODING_EMBSTRembstr
简单动态字符串REDIS_ENCODING_RAWraw
字典REDIS_ENCODING_HThashtable
双端链表REDIS_ENCODING_LINKEDLISTlinkedlist
双端链表REDIS_ENCODING_ZIPLISTziplist
整数集合REDIS_ENCODING_INTSETintset
跳跃表和字典REDIS_ENCODING_SKIPLISTskiplist
		表1-5   OBJECT ENCODING对不同编码的输出

通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的使用场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。举个栗子,在列表对象包含的元素比较少时,Redis使用压缩列表作为列表对象的底层实现:

  • 因为压缩列表比双端链表更节约内存,并且在元素比较少时,在内存中以连续块方式保存的压缩列表比起双端链表可以更快被载入到缓存中
  • 随着列表对象包含的元素越来越多,使用压缩列表来保存元素的优势逐渐消失时,对象就会将底层实现从压缩列表转换成功能更强、更适合保存大量元素的双端链表

其他类型的对象也会通过使用多种不同的编码来进行类似的优化,在接下来的内容中,我们将分别介绍Redis中的五种不同类型的对象,说明这些对象底层所使用的编码方式,列出对象从一种编码转换成另一种编码所需的条件,以及同一个命令在多种不同编码上的实现方法

字符串对象
字符串对象的编码可以是int、raw或者embstr。如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串结构的ptr属性中(将void *转换成long),并将字符串对象的编码设置为int
举个栗子,如果我们执行以下SET命令,那么服务器将创建一个如图1-1所示的int编码的字符串对象作为number键的值:

127.0.0.1:6379> SET number 10086
OK
127.0.0.1:6379> OBJECT ENCODING number
"int"

在这里插入图片描述
图1-1 int编码的字符串对象

如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于32字节,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值,并将对象的编码设置为raw。举个栗子,如果我们执行以下命令,那么服务器将创建一个如图1-2所示的raw编码的字符串作为store键的值

127.0.0.1:6379> SET story "Long, long, long, long, long ago there lived a king ..."
OK
127.0.0.1:6379> STRLEN story
(integer) 55
127.0.0.1:6379> OBJECT ENCODING story
"raw"

在这里插入图片描述
图1-2 raw编码的字符串对象
embstr编码是专门用于保存短字符串的一种优化编码方式,这种编码方式和raw编码一样,都使用redisObject结构和sdshdr结构来表示字符串对象,但raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间中依次包含redisObject和sdshdr结构,如图1-3所示
在这里插入图片描述图1-3 embstr编码创建的内存块结构

embstr编码的字符串对象在执行命令时,产生的效果和raw编码的字符串对象执行命令时产生的效果是相同的,但使用embstr编码的字符串来保存短字符串值有以下好处:

  • embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次
  • 释放embstr编码的字符串对象只需调用一次内存释放函数,而释放raw编码的字符串对象需要调用两次内存释放函数
  • 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存中,所以这种编码的字符串对象比起raw编码的字符串对象能够更好地利用缓存带来的优势

作为例子,以下命令创建一个embstr编码的字符串对象作为msg键的值,值对象的样子如图1-4所示

127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"

在这里插入图片描述
图1-4 embstr编码的字符串对象
最后要说的是,可以用long double类型表示的浮点数在Redis中也是作为字符串值来保存的。如果我们要保存一个浮点数到字符串对象里面,那么程序先将这个浮点数转换成字符串值,然后将其保存。举个栗子,执行以下代码将创建一个包含3.14的字符串对象

127.0.0.1:6379> SET pi 3.14
OK
127.0.0.1:6379> OBJECT ENCODING pi
"embstr"

在有需要的时候,程序会将保存在字符串对象中的字符串值转换回浮点数值,执行某些操作,然后再将执行操作所得的浮点数转换回字符串值,并继续保存在字符串对象里面。举个栗子,我们执行以下代码:

127.0.0.1:6379> SET pi 3.14
OK
127.0.0.1:6379> INCRBYFLOAT pi 3.0
"6.14"
127.0.0.1:6379> OBJECT ENCODING pi
"embstr

程序首先会取出字符串对象中保存的字符串值"3.14",将它转换回浮点数值3.14,然后把3.14和2.0相加得到5.14后在转换回字符串,并将字符串"5.14"保存到字符串对象中。表1-6总结并列出字符串对象保存各种不同类型的值所使用的编码方式

编码
可以用long类型保存的整数int
可以用long double类型保存的浮点数embstr或者raw
字符串值,或者因为长度太大而没办法用long类型表示的整数,又或者因为长度太大而没办法用long double类型表示的浮点数embstr或者raw
				表1-6   字符串对象保存各类型值的编码方式

编码的转换
int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的字符串对象。对于int编码的字符串对象来说,如果我们向对象执行了一些命令,使得对象保存的不再是整数值,而是一个字符串值,那么字符串对象将从int变为raw
下面的示例中,我们通过APPEND命令,向一个保存整数值的字符串追加一个字符串值,因为追加操作只能对字符串值执行,所以程序会将之前保存的整数值转换为字符串,然后再执行追加操作,操作的执行结果就是一个raw编码的、保存了字符串值的字符串对象

127.0.0.1:6379> SET number 10086
OK
127.0.0.1:6379> OBJECT ENCODING number
"int"
127.0.0.1:6379> APPEND number " is a good number!"
(integer) 23
127.0.0.1:6379> GET number
"10086 is a good number!"
127.0.0.1:6379> OBJECT ENCODING number
"raw"

另外,因为Redis没有为embstr编码的字符串对象编写任何相应的修改程序(只有int编码的字符串对象和raw编码的字符串对象有这些程序),所以embstr编码的字符串对象实际上是只读的。当我们对embstr编码的字符串对象执行任何修改命令时,程序先将对象的编码从embstr转换成raw,然后再执行修改命令。因为这个原因,embstr编码的字符串对象在执行修改命令之后,总会变成一个raw编码的字符串对象

以下代码展示了一个embstr编码的字符串对象在执行APPEND命令之后,对象的编码从embstr变为raw的例子:

127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"
127.0.0.1:6379> APPEND msg " again!"
(integer) 18
127.0.0.1:6379> OBJECT ENCODING msg
"raw"

字符串命令的实现
因为字符串键的值为字符串对象,所以用于字符串键的所有命令都是针对字符串对象来构建的,表1-7例举了其中一部分字符串命令,以及这些命令在不同编码的字符串对象下的实现方法

命令int编码的实现方法embstr编码的实现方法raw编码的实现方法
SET使用int编码保存值使用embstr编码保存值使用raw编码保存值
GET拷贝对象所保存的整数值,将这个拷贝转换成字符串值,然后向客户端返回这个字符串值直接向客户端返回字符串值直接向客户端返回字符串值
APPEND将对象转换成raw编码,然后按raw编码的方式执行此操作将对象转换成raw编码,然后按raw编码的方式执行此操作调用sdscatlen函数,将给定字符串追加到现有字符串的末尾
INCRBYFLOAT取出整数值并将其转换成long double类型的浮点数,对这个浮点数进行加法计算,然后将得出的浮点数结果保存起来取出字符串值并尝试将其转换成long double类型的浮点数,对这个浮点数进行加法计算,然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数,那么向客户端返回一个错误取出字符串值并尝试将其转换成long double类型的浮点数,对这个浮点数进行加法计算,然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数,那么向客户端返回一个错误
INCRBY对整数值进行加法计算,得出的计算结果会作为整数被保存起来embstr编码不能执行此命令,向客户端返回一个错误raw编码不能执行此命令,向客户端返回一个错误
DECRBY对整数值进行减法计算,得出的计算结果会作为整数被保存起来embstr编码不能执行此命令,向客户端返回一个错误raw编码不能执行此命令,向客户端返回一个错误
STRLEN拷贝对象所保存的整数值,将这个拷贝转换成字符串值,计算并返回这个字符串值的长度调用sdslen函数,返回字符串的长度调用sdslen函数,返回字符串的长度
SETRANGE将对象转换成raw编码,然后按raw编码的方式执行此命令将对象转换成raw编码,然后按raw编码的方式执行此命令将字符串特定索引上的值设置为给定的字符
GETRANGE拷贝对象所保存的整数值,将这个拷贝转换成字符串值,然后取出并返回字符串指定索引上的字符直接取出并返回字符串指定索引上的字符直接取出并返回字符串指定索引上的字符
					表1-7   字符串命令的实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值