redis学习系列(三-1)--redis基础类型初探(字符串)

本文详细介绍了Redis中对象的类型及编码方式,并通过实例演示了不同类型数据的存储形式及其转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博主从事java 只有1年多,越学习越觉得自己知道的很少,期间有时候还觉得自己java好像不错的样子,现在来看,扯淡,哈哈。

套用人生几大状态:其实很多时候人都是处于第一阶段,以为自己懂的很多,当然这是针对大多人的,少部分人又天赋,智商又高,搞起编程得心应手,而我们这种不聪明又没天赋的,只能尽量努力提高自己。时刻警醒,要做2阶段的人。求知探索。

1、不知道自己不知道(自以为是);
2、知道自己不知道(求知探索);
3、知道自己知道(探索规律);
4、不知道自己知道(空杯心态)。

此篇日志参考于如下资料:,自己写一遍,去redis环境测试一遍,能够加深不少印象,光看,还是不行的。

http://redisbook.com/ 

redis的对象 

redis使用对象来表示键值对,也就是说新建一个redis键值对时,会创建2个对象,一个是键对象,一个是值对象。每个对象都是由redisObject结构表示:

typedef struct redisObject {
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 指向底层实现数据结构的指针
    void *ptr;
    // ...
} robj;

这个结构先不去关心,只需要知道就行,有C基础应该就能看懂,C中的结构体就是用struct表示的。

类型

对象的type属性记录的是对象的类型,这个值可以是下面的一种:对于键值对的键来说的话,其实一般都是字符串对象,而值可能有多种多样的类型

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

实践

这个时候其实我对于命令还只是停留在set,get阶段,不过不要紧,先有个感性的认识,理性的认识慢慢来。

#String 类型

127.0.0.1:6379> set abc haha
OK
127.0.0.1:6379> get abc
"haha"
127.0.0.1:6379> type abc
string
127.0.0.1:6379> 

#list 类型

127.0.0.1:6379> type abclist
list
127.0.0.1:6379> 

#hash类型

127.0.0.1:6379> hmset srudent name tom age 15 address nanjing
OK

127.0.0.1:6379> hmget srudent name age address
1) "tom"
2) "15"
3) "nanjing"
127.0.0.1:6379> type srudent
hash

另外还有集合和有序集合这两个基本的类型,分别是set和zset,不去列举了。几个类型都在下面。OBJECT ENCODING命令可以查看编码方式

对象 对象 type 属性的值 TYPE 命令的输出
字符串对象 REDIS_STRING "string"
列表对象 REDIS_LIST "list"
哈希对象 REDIS_HASH "hash"
集合对象 REDIS_SET "set"
有序集合对象 REDIS_ZSET "zset"

编码和底层实现

这一段我也不清楚,暂时先记录下,作为对比,以后深入学习之后再说:

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


类型 编码 对象
REDIS_STRING REDIS_ENCODING_INT 使用整数值实现的字符串对象。
REDIS_STRING REDIS_ENCODING_EMBSTR 使用 embstr 编码的简单动态字符串实现的字符串对象。
REDIS_STRING REDIS_ENCODING_RAW 使用简单动态字符串实现的字符串对象。
REDIS_LIST REDIS_ENCODING_ZIPLIST 使用压缩列表实现的列表对象。
REDIS_LIST REDIS_ENCODING_LINKEDLIST 使用双端链表实现的列表对象。
REDIS_HASH REDIS_ENCODING_ZIPLIST 使用压缩列表实现的哈希对象。
REDIS_HASH REDIS_ENCODING_HT 使用字典实现的哈希对象。
REDIS_SET REDIS_ENCODING_INTSET 使用整数集合实现的集合对象。
REDIS_SET REDIS_ENCODING_HT 使用字典实现的集合对象。
REDIS_ZSET REDIS_ENCODING_ZIPLIST 使用压缩列表实现的有序集合对象。
REDIS_ZSET REDIS_ENCODING_SKIPLIST 使用跳跃表和字典实现的有序集合对象。

字符串对象

字符串对象的编码可以是 int ,raw,embstr

1.设置的是数字型的键值对,编码就是int

127.0.0.1:6379> set num 10010
OK
127.0.0.1:6379> type num
string
127.0.0.1:6379> object encoding num
"int"
127.0.0.1:6379> 

底层结构如下:图直接copy下来,可以看见ptr指针直接指向 这个值

digraph {    label = "\n 图 8-1    int 编码的字符串对象";    rankdir = LR;    node [shape = record];    redisObject [label = " redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_INT | <ptr> ptr | ... "];    node [shape = plaintext];    number [label = "10086"]    redisObject:ptr -> number;}

2.设置的是字符串键值对,这其中根据字符串长度的不同,会有不同的表现

2.1 长度小于39的话,会使用embstr的编码

127.0.0.1:6379> set key1 abc
OK
127.0.0.1:6379> type key1
string
127.0.0.1:6379> object encoding key1
"embstr"
127.0.0.1:6379> 

embstr是专门针对短字符串的一种优化,和raw一样,都使用redisObject和sdshdr结构表示,但是embstr只调用一次内存分配函数来分配一块连续的空间

digraph {    label = "\n 图 8-3    embstr 编码创建的内存块结构";    node [shape = record];    embstr [ label = " { redisObject | { type | encoding | <ptr> ptr | ... } } |  { sdshdr | { free | len | <buf> buf }} " ];}

因此2.1中set的 key1就如下结构:图是直接copy的,可以看见sdshdr中有free,len和buf,buf中存放的是字符串,以\0结尾,和C一致

digraph {    label = "\n 图 8-4    embstr 编码的字符串对象";    node [shape = record];    embstr [ label = " { redisObject | { type \n REDIS_STRING | encoding \n REDIS_ENCODING_EMBSTR | <ptr> ptr | ... } } |  { sdshdr | { free \n 0 | len \n 5 | { buf | { <buf> 'h' | 'e' | 'l' | 'l' | 'o' | '\\0'}} }} " ];    embstr:ptr -> embstr:buf;}

2.2 长度超过 39,使用的是 raw编码方式

127.0.0.1:6379> set key2 "abc     cdrfdsertg      kgjfhdurhfg     hff"
OK
127.0.0.1:6379> type key1
string
127.0.0.1:6379> type key2
string
127.0.0.1:6379> object encoding key2
"raw"
127.0.0.1:6379> 

raw方式的不同点在于调用两次内存分配函数创建redisObject和sdshdr结构,也就是这种方式的存放地址不是连续的,但是内部都是一样的

digraph {    label = "\n 图 8-2    raw 编码的字符串对象";    rankdir = LR;    node [shape = record];    redisObject [label = " redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_RAW | <ptr> ptr | ... "];    sdshdr [label = " <head> sdshdr | free \n 0 | len \n 43 | <buf> buf"];    buf [label = " { 'L' | 'o' | 'n' | 'g' | ... | 'k' | 'i' | 'n' | 'g' | ' ' | '.' | '.' | '.' | '\\0' } " ];    //    redisObject:ptr -> sdshdr:head;    sdshdr:buf -> buf;}

2.3浮点数也是一样可以保存的,但是会转换成字符串

127.0.0.1:6379> set key3 3.14
OK
127.0.0.1:6379> type key3
string
127.0.0.1:6379> object encoding key3
"embstr"
127.0.0.1:6379> 

总结下:

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

编码的转换

int 和embstr子啊特定条件会向raw转换,不难理解,如果int 拼接字符串或者字符串长度太长,会转换

比如1:

127.0.0.1:6379> get num
"10010"
127.0.0.1:6379> append num "is a num"
(integer) 13
127.0.0.1:6379> get num
"10010is a num"
127.0.0.1:6379> object encoding num
"raw"
127.0.0.1:6379> 

比如2: redis中没有对embstr编码的字符串提供修改程序,所以embstr都是只读的,因此任何对embstr做的修改,都会先将embstr转换成raw,再执行修改。

127.0.0.1:6379> set key5 abc 
OK
127.0.0.1:6379> object encoding abc
"embstr"
127.0.0.1:6379> append key5 " is a english"
(integer) 16
127.0.0.1:6379> obejct encoding key5
(error) ERR unknown command 'obejct'
127.0.0.1:6379> object encoding key5
"raw"
127.0.0.1:6379> 

字符串命令:

命令 int 编码的实现方法 embstr 编码的实现方法 raw 编码的实现方法
SET 使用 int 编码保存值。 使用 embstr 编码保存值。 使用 raw 编码保存值。
GET 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 然后向客户端返回这个字符串值。 直接向客户端返回字符串值。 直接向客户端返回字符串值。
APPEND 将对象转换成 raw 编码, 然后按 raw编码的方式执行此操作。 将对象转换成 raw 编码, 然后按 raw编码的方式执行此操作。 调用 sdscatlen 函数, 将给定字符串追加到现有字符串的末尾。
INCRBYFLOAT 取出整数值并将其转换成 longdouble 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 取出字符串值并尝试将其转换成long double 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误。 取出字符串值并尝试将其转换成 longdouble 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误。
INCRBY 对整数值进行加法计算, 得出的计算结果会作为整数被保存起来。 embstr 编码不能执行此命令, 向客户端返回一个错误。 raw 编码不能执行此命令, 向客户端返回一个错误。
DECRBY 对整数值进行减法计算, 得出的计算结果会作为整数被保存起来。 embstr 编码不能执行此命令, 向客户端返回一个错误。 raw 编码不能执行此命令, 向客户端返回一个错误。
STRLEN 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 计算并返回这个字符串值的长度。 调用 sdslen 函数, 返回字符串的长度。 调用 sdslen 函数, 返回字符串的长度。
SETRANGE 将对象转换成 raw 编码, 然后按 raw编码的方式执行此命令。 将对象转换成 raw 编码, 然后按 raw编码的方式执行此命令。 将字符串特定索引上的值设置为给定的字符。
GETRANGE 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 然后取出并返回字符串指定索引上的字符。 直接取出并返回字符串指定索引上的字符。 直接取出并返回字符串指定索引上的字符。












1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
1. 用户管理模块 用户注册与认证: 注册:用户填写身份信息(姓名、身份证号、手机号)、设置登录密码(需符合复杂度要求),系统生成唯一客户号 登录:支持账号(客户号 / 手机号)+ 密码登录,提供验证码登录、忘记密码(通过手机验证码重置)功能 身份验证:注册后需完成实名认证(模拟上传身份证照片,系统标记认证状态) 个人信息管理: 基本信息:查看 / 修改联系地址、紧急联系人、邮箱等非核心信息(身份证号等关键信息不可修改) 安全设置:修改登录密码、设置交易密码(用于转账等敏感操作)、开启 / 关闭登录提醒 权限控制:普通用户仅能操作本人账户;管理员可管理用户信息、查看系统统计数据 2. 账户与资金管理模块 账户管理: 账户创建:用户可开通储蓄卡账户(默认 1 个主账户,支持最多 3 个子账户,如 “日常消费账户”“储蓄账户”) 账户查询:查看各账户余额、开户日期、状态(正常 / 冻结)、交易限额 账户操作:挂失 / 解挂账户、申请注销账户(需余额为 0) 资金操作: 转账汇款:支持同行转账(输入对方账户号 / 手机号),需验证交易密码,可添加常用收款人 存款 / 取款:模拟存款(输入金额增加余额)、取款(输入金额减少余额,需不超过可用余额) 交易记录:按时间、类型(转入 / 转出 / 存款 / 取款)查询明细,显示交易时间、金额、对方账户(脱敏显示)、交易状态 3. 账单与支付模块 账单管理: 月度账单:自动生成每月收支明细,统计总收入、总支出、余额变动 账单查询:按月份、交易类型筛选账单,支持导出为 Excel 格式 还款提醒:若有贷款(简化版可模拟),系统在还款日 3 天前发送提醒 快捷支付: 绑定支付方式:添加银行卡(系统内账户)作为支付渠道 模拟消费:支持输入商户名称和金额,完成支付(从账户余额扣减) 支付记录:保存所有消费记录,包含商户、时间、金额、支付状态 4.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值