设为首页 收藏本站
查看: 955|回复: 0

[经验分享] Redis的字符串与散列类型

[复制链接]

尚未签到

发表于 2016-12-20 09:17:27 | 显示全部楼层 |阅读模式


  • String 类型简介
  • String 类型的命令操作
  • Hash 类型简介
  • Hash 类型的命令操作

String 数据类型简介


  • Redis 数据库内部结构
  • 键值的语法约定
  • String  类型介绍

一、Redis 数据库内部结构
Redis 中的每个数据库,都由一个redis.h/redisDb 结构表示:
伪代码:

typedef struct redisDb {
int   id;   // 保存着数据库以整数表示的号码
dict  *dict;  // 保存着所有键值对数据,这个属性也被称为键空间(key space)
dict  *expires;  // 保存着键的过期信息
dict  *blocking_keys;  // 实现列表阻塞原语,在列表类型一章有详细的讨论
dict  *watched_keys;// 用于实现WATCH 命令
} redisDb;

因为 Redis 是一个键值对数据库( key-value pairs database ),所以它的数据库本身也是一个字典(俗称 key space)
字典的键是一个字符串对象。
字典的值则可以是包括字符串、列表、哈希表、集合或有序集在内的任意一种Redis 类型对象。
在 redisDb  结构的 dict  属性中,保存着数据库的所有键值对数据。
下图展示了一个包含 number 、book 、message 三个键的数据库—其中 number
键是一个列表,列表中包含三个整数值;book  键是一个哈希表,表中包含三个键
值对;而 message  键则指向另一个字符串。
DSC0000.png
String 数据类型简介 — 键值的语法约定

命令
      Redis中的命令不区分大小写,SET与set效果是一样的。
主键(key)
可以用任何二进制序列作为key值,从形如“ foo”的简单字符串到一个JPEG文件的内容都可以。空字符串也是有效key值。
String 数据类型简介 — 键值的语法约定
关于key的规则
可以用任何二进制序列作为key值。
格式约定:object-type:id:field。
不用太长的键值。不仅消耗内存,而且在数据查找中计算成本很高。
太短的键值通常也不是好主意,可读性差。
      如用“user:1000:password” 来代替“u:1000:pwd”。
String类型介绍
String 是 Redis 最基本的类型,而且 String 类型是二进制安全的。意思是 Redis 的
String可以包含任何数据。比如jpg图片或者序列化的对象。从内部实现来看其实
String可以看作byte数组,最大上限是1G字节。下面是String类型的定义。
伪代码:
struct sdshdr {   
long  len;       //len是buf数组的长度
long  free;     //free是数组中剩余可用字节数
char  buf[ ];  //char数组用于存贮实际的字符串内容
}String;

应用场景
         String是最常用的一种数据类型,普通的key/value存储。
实现方式
         String在Redis内部存储默认就是一个字符串,被  RedisObject 所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时 RedisObject 的 encoding 字段为int。
整体结构如下:
DSC0001.png
String类型的命令操作


  • 新增相关命令
  • 查询相关命令
  • 修改相关命令
  • 删除及其它命令
  • 场景案例

新增相关命令
Set
语法:set key value
解释:把值value赋给key,如果key不存在,新增;否则,更新。
Setnx
语法:setnx  key  value
解释:只 insert 不 update,即,仅仅key不存在时,则设置key的值为value,并返回1,否则返回0  。setnx 是set if not exists 的缩写。
Setex
语法: setex key seconds value
解释:设置key的过期时间和值。过期时间seconds单位是秒。设置过期时间和值是原子操作,如果redis仅仅当做缓存,这个很命令很有用。
mset
语法:mset  key  value  [key  value ...]
解释:同时设置多个key-value。
msetnx
语法:msetnx key value  [key value ...]
解释:所有key都不存在才执行set操作。
查询相关命令
get
语法:get key
解释:获取key所set的值。
mget
语法: mget key [key]
解释:批量获取key的值。程序一次获取多个值,可以减少网络连接损耗。
getrange
语法:getrange  key star end
解释:获取存储在key中value的字串。字符串的截取有star和end决定,字符串的第一个字符编号是0,第二个是1,一次类推;如果是负数,-1是最后一个字符,-2是倒数第二个字符,一次类推。
修改相关命令
getset
语法:getset key value
解释:设置key的值,并返回key的旧值。
append
语法:append key value
解释:key存在,在旧值的后面追加value;key不存在,直接set,返回长度。
setrange (替换部分子串)
语法:setrange  key offset value
解释:用value重写key值的一部分,偏移量由offset指定 。
Incr/decr
语法:incr/decr  key
解释:key中如果存储的是数字,则可以通过incr递增key的值,返回递增后的值。如果key不能存在,视为初始值为0。
Incrby/decrby
语法:incrby key increment
解释:用指定的步长增加key存储的数字。如果步长increment是负数,则减。
注意:递增递减系列的函数,只能对保存的是数字的key操作,不能是字符串。 
del
语法:del key [key]
解释:删除指定的key,返回删除key的个数。
strlen
语法:strlen key
解释:获取key中所存储值的长度。
场景案例
案例:博客系统的设计与开发
需求与实现
文章的访问量:定义键 post:articleID:pageView,通过INCR命令递增
自增ID:定义键article:count,通过INCR递增
存储文章的数据:伪代码如下
首先获得新文章的ID
              $postID = INCR posts:count
将博客文章的诸多元素序列化成字符串
              $serializedPost = serialize($title,$content,$author,$time)
把序列化后的字符串存入一个字符串类型的键中
              SET post:$postID:data,$serializedPost
获取文章数据的伪代码
从Redis中读取文章的数据
              $serializePost=GET post:42:data
将文章数据反序列化成文章的各个元素
               $title,$content,$author,$time = unserialize($serializePost)
获取并递增文章的访问量
              $count=INCR post:42:pageView
原理图如下:
DSC0002.png
Hash类型简介

  • Hash数据类型的概念
  • Hash数据类型的底层实现
  • Hash数据类型的使用场景

Hash数据类型的概念
Redis hash 是一个 string 类型的 field 和 value 的映射表。可以将 Redis 中的 Hash 类型看成具有 String
Key 和 String  Value 的 map容器。将一个对象存储为 Hash 类型,较于每个字段
都存储成 string 类型更能节省内存。每一个Hash可以存储2^32 -1个键值对。
Hash数据类型的底层实现
Hash 对应 Value 内部实际就是一个 HashMap,实际这里会有2种不同实现,这个
Hash的成员比较少时 Redis 为了节省内存会采用类似一维数组的方式来紧凑存储即
zipmap(压缩列表),而不会采用真正的 HashMap 结构,对应的value
redisObject 的 encoding为 zipmap,当成员数量增大时会自动转成真正的
HashMap,此时 encoding 为ht(哈希表)。
DSC0003.png
dict.h/dict 给出了这个字典的定义:

Typedef  struct  dict {
dictType *type;  // 特定于类型的处理函数
void *privdata;  // 类型处理函数的私有数据
dictht ht[2];       // 哈希表(2 个)
int rehashidx;  // 记录rehash 进度的标志,值为-1 表示rehash 未进行
int iterators;    // 当前正在运作的安全迭代器数量
} dict;
//字典所使用的哈希表实现由 dict.h/dictht 类型定义:
typedef struct dictht {
dictEntry  **table; // 哈希表节点指针数组(俗称桶,bucket)
unsigned long size; // 指针数组的大小
unsigned long sizemask; // 指针数组的长度掩码,用于计算索引值
unsigned long used; // 哈希表现有的节点数量
} dictht;
//dictEntry 都保存着一个键值对,以及一个指向另一个 dictEntry 结构的指针:
typedef struct dictEntry {
void *key;// 键
union {
void *val;   …
} v; // 值
struct dictEntry *next;// 链往后继节点
} dictEntry;

整个字典结构可以表示如下:
DSC0004.png
Hash类型简介 — 使用场景
Hash类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,
而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、
name和price的3个字段来存储该辆汽车的颜色、名称和价格。个人感觉基本跟java中的domain
差不多。
使用场景
Hash类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,
而字段值则存储属性值。例如要存储ID为2的汽车对象,可以分别使用名为color、
name和price的3个字段来存储该辆汽车的颜色、名称和价格。
DSC0005.png
Hash类型的命令操作
新增相关命令
hset
语法:hset key field value
解释:设置hash表key中的field的值。如果hash表不存在,则创建,并执行设置field的值,如果hash表存在,值field的值覆盖。
hmset
语法:hash key  field  value[key value]
解释:批量设置hash表key的域,如果原来有值就进行覆盖。
hsetnx
语法:hsetnx key field value
解释:仅仅当field域不存在时,设置hash表field的值。
查询相关命令
hget
语法:hget key field
解释:获取哈希表key的field值。
hmget
语法:hmget key field[field]
解释:批量获取hash表的filed。
hgetall
语法:hgetall key
解释:获取hash表的所有域值。
hexits
语法:hexists key field
解释:判断hash表中是否存在某个域。
hkeys
语法:hkeys key
解释:获取hash表的所有域。
hvals
语法:hvals key
解释:获取hash表的所有域值。
hincrby
语法:hincrby key field increment
解释:hash表field域的数值增加步长increment,如果increment是负值,则是递减。如果域不存在,初始值视为0。
删除及其它相关命令
hdel
语法:hdel key field[field]
解释:删除hash的域,如果指定多个field,则删除多个。
hlen
语法:hlen key
解释:获取hash的域数量。

场景案例
该案例引自极客学院,本人未进行尝试。
DSC0006.png

本文小结
   1、redis中的数据库内部结构。
   2、redis中的String类型及常用命令、使用场景。
   3、redis中的hash表学习及常用命令、使用场景。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-316782-1-1.html 上篇帖子: redis渐入佳境(07) 登录密码设置及主从复制 下篇帖子: Redis性能问题和解决方案
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表