Redis | 您所在的位置:网站首页 › redis中hash存储 › Redis |
Redis五大数据类型
Redis的介绍Redis常用类型stringstring 类型数据的基本操作string 类型数据的扩展操作数据增减操作数据时效性设置string类型数据的一些其他操作
string 类型数据操作的注意事项string 类型应用场景
hashhash 类型数据的基本操作hash 类型数据扩展操作hash 类型数据操作的注意事项hash 类型应用场景电商网站购物车设计与实现商家抢购活动
Redis的介绍
Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。它支持多种类型的数据结构,如 字符串(string),散列(hashes),列表(list),集合(sets),有序集合(sorted sets)与范围查询,bitmaps,hyperloglogs和地理空间(geospatial)索引半径查询。Redis内置了 复制(replocation),LUA脚本(Lua scripting),LRU驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘持久化(persistence),并通过 Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(high availability) Redis常用类型 string Stringhash HashMaplist LinkedListset HashSetsorted_set TreeSetredis 数据存储格式 redis自身是一个Map,其中所有的数据都是采用key:value的形式存储数据类型指的是存储的数据的类型,也就是value部分的类型,key部分永远都是字符串 string 存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型存储数据的格式:一个存储空间保存一个数据存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用 string 类型数据的基本操作 添加/修改数据set key value 获取数据get key 删除数据del key 127.0.0.1:6379> set name maomao OK 127.0.0.1:6379> get name "maomao" 127.0.0.1:6379> del name (integer) 1 127.0.0.1:6379> get name (nil) 添加/修改多个数据mset key1 value1 key2 value2 … 获取多个数据mget key1 key2 … 获取数据字符串长度(字符串个数)strlan key 追加信息到原始信息后部(如果原始信息存在就追加,否则新建)append key value 127.0.0.1:6379> mset k1 a k2 b k3 c OK 127.0.0.1:6379> mget k1 k2 k3 1) "a" 2) "b" 3) "c" 127.0.0.1:6379> set name maomao OK 127.0.0.1:6379> strlen name (integer) 6 127.0.0.1:6379> append hello world (integer) 5 127.0.0.1:6379> get hello "world" 127.0.0.1:6379> append name zhu (integer) 9 127.0.0.1:6379> get name "maomaozhu" string 类型数据的扩展操作 数据增减操作业务场景 大型企业级应用中,分表操作是基本操作,使用多张表存储同类型数据,但是对应的主键 id 必须保证统一性,不能重复。Oracle 数据库具有 sequence 设定,可以解决该问题,但是 MySQL数据库并不具有类似的机制,那么如何解决?解决方案 设置数值数据增加指定范围的值 incr key incrby key increment incrbyfloat key increment 设置数值数据减少指定范围的值 decr key decrby key increment redis本身就是单线程的,所以可以用这种方式解决分布式ID的问题 127.0.0.1:6379> set num 0 OK 127.0.0.1:6379> incr num # 自增1 (integer) 1 127.0.0.1:6379> incr num (integer) 2 127.0.0.1:6379> get num "2" 127.0.0.1:6379> decr num # 自减1 (integer) 1 127.0.0.1:6379> decr num (integer) 0 127.0.0.1:6379> decr num (integer) -1 127.0.0.1:6379> get num "-1" 127.0.0.1:6379> incrby num 10 # 可以设置步长 指定增量 (integer) 9 127.0.0.1:6379> incrby num 10 (integer) 19 127.0.0.1:6379> decrby num 9 (integer) 10 127.0.0.1:6379> incrbyfloat num 2.5 # 小数 "12.5" 127.0.0.1:6379> incrby num 3.5 # incrby只能是int类型 (error) ERR value is not an integer or out of rangestring 作为数值操作 string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算。redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发 带来的数据影响。注意:按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错。 9223372036854775807(java中long型数据最大值,Long.MAX_VALUE)redis 用于控制数据库表主键id,为数据库表主键提供生成策略,保障数据库表的主键唯一性。适用于所有数据库,且支持数据库集群 数据时效性设置业务场景 海选投票,只能通过微信投票,每个微信号每 4 小时只能投1票。电商商家开启热门商品推荐,热门商品不能一直处于热门期,每种商品热门期维持3天,3天后自动取消热门。新闻网站会出现热点新闻,热点新闻最大的特征是时效性,如何自动控制热点新闻的时效性。解决方案 设置数据具有指定的生命周期 setex key seconds value psetex key milliseconds value 设置独立的数据 setnx key value 127.0.0.1:6379> setex tel 10 '123456789' # 设置一个keys的值为num 10秒后过期 OK 127.0.0.1:6379> ttl tel # 生命周期 (integer) 6 127.0.0.1:6379> get tel "123456789" 127.0.0.1:6379> ttl tel (integer) 1 127.0.0.1:6379> get tel (nil) 127.0.0.1:6379> setnx subject 'redis' # 如果key不存在 则创建相应的 (integer) 1 127.0.0.1:6379> setnx subject 'mongodb' # 如果key存在 则创建失败 (integer) 0 127.0.0.1:6379> get subject "redis" 127.0.0.1:6379> psetex zhu 5000 'zhuzhu' # 毫秒 OK 127.0.0.1:6379> ttl zhu (integer) 1 127.0.0.1:6379> get zhu (nil) 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k4 (nil) 127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作,要么一起成功,要么一起失败 (integer) 0 127.0.0.1:6379> get k4 (nil) 127.0.0.1:6379> get k1 "v1"redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作 string类型数据的一些其他操作获取字符串的范围 getrange key start end 替换指定范围的字符串 setrange key offset value 127.0.0.1:6379> set name 'hello,maomao' OK 127.0.0.1:6379> get name "hello,maomao" 127.0.0.1:6379> getrange name 0 3 "hell" 127.0.0.1:6379> getrange name 0 -1 "hello,maomao" 127.0.0.1:6379> setrange name 2 mmm (integer) 12 127.0.0.1:6379> get name "hemmm,maomao" 127.0.0.1:6379> setrange name 0 ilove (integer) 12 127.0.0.1:6379> getrange name 0 -1 "ilove,maomao" 先get再setgetset key value 127.0.0.1:6379> getset db redis # 如果不存在值 则返回 nil (nil) 127.0.0.1:6379> get db "redis" 127.0.0.1:6379> getset db mongoDB # 如果存在值,获取原来的值,并设置新的值 "redis" 127.0.0.1:6379> get db "mongoDB" 储存一个对象 set user:1 {name:maomao,age:18} # 设置一个user:1 对象 值为 json字符来保存一个对象! 这里的key是一个巧妙地设计:user:{id}:{filed} , 如此设计在Redis中完全ok 127.0.0.1:6379> mset user:1:name maomao user:1:age 18 user:1:gender nv OK 127.0.0.1:6379> mget user:1:name user:1:age user:1:gender 1) "maomao" 2) "18" 3) "nv" string 类型数据操作的注意事项 数据操作不成功的反馈与数据正常操作之间的差异 表示运行结果是否成功 (integer) 0 → false 失败 (integer) 1 → true 成功表示运行结果值 (integer) 3 → 3 3个 (integer) 1 → 1 1个 数据未获取到 (nil)等同于null数据最大存储量 512MB数值计算最大范围(java中的long的最大值) 9223372036854775807 string 类型应用场景主页高频访问信息显示控制,例如B站up主,主页显示粉丝数与,获赞数,播放数 key 的设置约定 数据库中的热点数据key命名惯例 表名 :主键名 :主键值 : 字段名 order : id : 294375951 : name equip : id : 390472345 : type news : id : 202004150 : title hash 新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息需要的存储结构:一个存储空间保存多个键值对数据hash类型:底层使用哈希表结构实现数据存储关于哈希表参考 大佬的文章 hash存储结构优化 如果field数量较少,存储结构优化为类数组结构如果field数量较多,存储结构使用HashMap结构 hash 类型数据的基本操作添加/修改数据 hset key field value 获取数据 hget key field hgetall key 删除数据 hdel key field1 [field2] 127.0.0.1:6379> hset user name xiaotian (integer) 1 127.0.0.1:6379> hset user age 20 (integer) 1 127.0.0.1:6379> hset user gender nan (integer) 1 127.0.0.1:6379> hgetall user 1) "name" 2) "xiaotian" 3) "age" 4) "20" 5) "gender" 6) "nan" 127.0.0.1:6379> hget user name "xiaotian" 127.0.0.1:6379> hget user gender "nan" 127.0.0.1:6379> hdel user gender (integer) 1 127.0.0.1:6379> hgetall user 1) "name" 2) "xiaotian" 3) "age" 4) "20" 添加/修改多个数据hmset key field1 value1 field2 value2 … 获取多个数据hmget key field1 field2 … 获取哈希表中字段的数量hlen key 获取哈希表中是否存在指定的字段hexists key field 127.0.0.1:6379> hmget user name age 1) "xiaotian" 2) "20" 127.0.0.1:6379> hmset user name feifei age 22 weight 46 OK 127.0.0.1:6379> hgetall user 1) "name" 2) "feifei" 3) "age" 4) "22" 5) "weight" 6) "46" 127.0.0.1:6379> hlen user # 获取的是field的数量 (integer) 3 127.0.0.1:6379> hexists user age # 判断是否存在指定字段 (integer) 1 127.0.0.1:6379> hexists user height (integer) 0 hash 类型数据扩展操作 获取哈希表中所有的字段名或字段值hkeys key hvals key 设置指定字段的数值数据增加指定范围的值hincrby key field increment hincrbyfloat key field increment 127.0.0.1:6379> hkeys user # 所有的字段名 1) "name" 2) "age" 3) "weight" 127.0.0.1:6379> hvals user # 所有的字段值 1) "feifei" 2) "22" 3) "46" 127.0.0.1:6379> hincrby user age 1 (integer) 23 127.0.0.1:6379> hincrby user weight 10 # 指定增量 (integer) 56 127.0.0.1:6379> hincrby user weight -5 # 指定减量 (integer) 51 hash 类型数据操作的注意事项 hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)每个 hash 可以存储 2^32 - 1 个键值对hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈 hash 类型应用场景 电商网站购物车设计与实现
解决方案 以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息将商品编号作为field,购买数量作为value进行存储添加商品:追加全新的field与value浏览:遍历hash更改数量:自增/自减,设置value值 删除商品:删除field清空:删除key id:001指用户id g01 g02 指商品id 127.0.0.1:6379> hmset id:001 g01 100 g02 200 OK 127.0.0.1:6379> hmset id:002 g02 10 g04 8 g05 100 OK 127.0.0.1:6379> hset id:001 g03 5 (integer) 1 127.0.0.1:6379> hgetall id:001 1) "g01" 2) "100" 3) "g02" 4) "200" 5) "g03" 6) "5" 127.0.0.1:6379> hdel id:001 g01 (integer) 1 127.0.0.1:6379> hgetall id:001 1) "g02" 2) "200" 3) "g03" 4) "5" 127.0.0.1:6379> hincrby id:001 g03 3 (integer) 8 127.0.0.1:6379> hgetall id:001 1) "g02" 2) "200" 3) "g03" 4) "8"但目前这样是不够的,当前仅仅是将数据存储到了redis中,并没有起到加速的作用,商品信息还需要二次查询数据库 解决方案 每条购物车中的商品记录保存成两条field field1专用于保存购买数量 命名格式:商品id:nums 保存数据:数值field2专用于保存购物车中显示的信息,包含文字描述,图片地址,所属商家信息等 命名格式:商品id:info 保存数据:json 127.0.0.1:6379> hmset id:003 g01:nums 100 g01:info {diannao,8000} OK 127.0.0.1:6379> hgetall id:003 1) "g01:nums" 2) "100" 3) "g01:info" 4) "{diannao,8000}" 127.0.0.1:6379> hmset id:004 g01:nums 50 g01:info {diannao,8000} OK 127.0.0.1:6379> hgetall id:004 1) "g01:nums" 2) "50" 3) "g01:info" 4) "{diannao,8000}"但这样又出现新的问题 就是g01:info是重复的,因此我们把field2作为独立hash 专门用来保存商品信息的hash
hsetnx key field value 127.0.0.1:6379> hset id:004 g01:nums 200 (integer) 0 127.0.0.1:6379> hget id:004 g01:nums "200" 127.0.0.1:6379> hsetnx id:004 g01:nums 400 (integer) 0 127.0.0.1:6379> hsetnx id:004 g05:nums 400 (integer) 1 127.0.0.1:6379> hgetall id:004 1) "g01:nums" 2) "200" 3) "g01:info" 4) "{diannao,8000}" 5) "g05:nums" 6) "400" 商家抢购活动双11活动日,iphone商家对iPhone12,iPad Pro, MacBook Pro的5000元、6000元、10000元商品推出抢购活动,每种商 品抢购上限100台 解决方案 以商家id作为key将参与抢购的商品id作为field将参与抢购的商品数量作为对应的value抢购时使用降值的方式控制产品数量 127.0.0.1:6379> hmset shop:001 iphone12 100 ipad 100 macbook 100 OK 127.0.0.1:6379> hincrby shop:001 iphone12 -1 (integer) 99 127.0.0.1:6379> hincrby shop:001 macbook -20 (integer) 80 127.0.0.1:6379> hgetall shop:001 1) "iphone12" 2) "99" 3) "ipad" 4) "100" 5) "macbook" 6) "80" |
CopyRight 2018-2019 实验室设备网 版权所有 |