你真的了解Redis的String数据结构吗--redis之面试官爱我系列(1)

各位好,我是华华
最近做一个上线的项目,计划把redis各种机制用到项目里所以学redis也学了很久
redis 是面试官很爱问的东西,尤其是对已经工作了的人
它在开发中的地位也不言而喻
今天开始redis的知识系列 ,让你看到不一样的redis
让你看了华华的文章后,面试官从此爱上你。


今天讲Redis最基本的数据结构

String(字符串),类似Arraylist
HashMap<String,String>==>string
是最基本的数据类型,⼀个健最⼤能存储512MB,String 类型是⼆进制安全的
String可以包含任何数据
啥都不说实诚人先上图为敬:

在这里插入图片描述

用法:

a.CURD:

set 增

get 查

del 删

exists 是否存在

过期和set命令扩展:

getset

先取出原来的值,再设置新值。getset + key +value 返回旧值(替换)

2.setnx key “xxxx” :

如果key的值不存在设置它为xxxx (set +exists) 成功返回1,未成功返回0
getset 先取出原来的值,再设置新值。getset + key +value

3.settex key n “xxx” :

设置它的值为xxx有效期为n(set+expire)

返回旧值

b字符串操作

strlen key //查看字符串的⻓度
append key “xxx” //增加元素(⽅法返回当前⻓度
getrange
c.范围内操作
getrange key n m 获取n位到m位的值(跟数组⼀样初始位是0,-1表示最后⼀位)(subString)
settrange key n newstr,设置从n位置开始,替换指定位置为新的字符串
d自增自减:

incr:

如果key是空会自动建立一个空间(自增有范围超过singed long 范围就会报错(92233372036854774807))

incrby key n 数字元素增加n

decr

decrby key n 数字元素减少n(在多线程会⽤)

e批量操作
1.mget key1 key2 key3 key4

统⼀得到四个key的值(参数接收多个key,结果返回多个value)
2.mset key xxx1 key2 xxx2 key3 xxx3

⼀次设置多个key值 参数本身是⼀个map(mset + key1+value1 +key2 +value2)
3.msetnx key1 “xxx1” key2 “xxx2”.

如果key的值不存在设置它为xxxx (set +exists)
命令总结
CURD:set/get/del/get set/setex/setnx
批量:mget/mset/msetnx
字符串操作:append/strlen/gentrange/setrange
⾃增/⾃减:incr/incrby/decr/decrby

原理:

扩容策略:

redis 的字符串是动态的字符串, 内部结构类Arraylist 采⽤预分配冗余空间的⽅式减⼩内存的频繁分
配,内部为字符串分配的实际空间⼀般⾼于字符串⻓度,当字符串⻓度<1MB时,扩容⽅式是直接加
倍,如果>1MB ⼀次扩容只扩1MB。直到扩⼤到512MB

底层存储:

当字符串整体在64字节以内时,会以emdstr存储

当字符串整体超过64字节Redis认为它是一个大字符串会以raw形式存储

一个Redis字符串分为两大部分RedisObject(对象头结构)和SDS

在这里插入图片描述

一个Redis对象(这里理解成一个你add进去的一个单元吧)

其中一大部分叫RedisObject对象头结构,这是所有数据结构类型的Redis对象都有的一个结构

RedisObject:

它有5大部分:(虽然redis是用c写的,但这里确实可以用java对象的属性来理解)

type:描述类型

encoding:秒速存储形式

lru:存储对象的LRU信息:描述使用频率这样子

refcount:引用计数(当计数为0时候,对象被销毁,内存被回收)

ptr:存储着对象内容的具体存储位置

//整个对象头所有部分加起来占了16字节

SDS:

这里就是具体存储的容器,它的数据结构乃至扩容机制和java的ArrayList非常像

capacity:数组容量,是数组本身的长度(包括无用的存储空间)(1byte)

len:数组长度,一个数组实际可用的长度(1byte)

falgs:特殊标志位(1byte)

byte []content:内置数组

//所以有种剥洋葱的感觉,一层层的拨开才看到真正存东西的数组

//这个SDS最少需要占3个字节

struct SDS<T>{
    T capactiy;
    T len;
    byte flags;
    byte[] content;
}

(SDS结构:在结构中使用了泛型T,这是希望当字符串很短时,len 和capacity可以使用byte和short来表示,(作为程序员真的好扣))

前面说到整体在64字节以内时是以embste形式存储的、

(原因:jemalloc、tcmalloc等分配内存大小都是2/4/8/16/32/64,内存超过64字节就认为是大字符串)

但是整体内有19字节(16+3)而且content字符串是以字节null结尾的字符串这个null又占了1个字节

在embstr存储形式中,留给content这个数组的空间只有44字节。

embstr存储形式与raw存储形式区别:

两者最大的区别就是RedisObject对象头和SDS对象是否连续存在在一起

embstr是使用malloc(动态内存分配函数)方法分配一次

raw是需要使用两次malloc方法,两部分地址一般是不连续

在这里插入图片描述

用途

缓存用户信息,我们将用户信息结构体用JSON序列化成字符串,然后将序列化后的字符串塞进redis来缓存,同样取用户信息会经过一次反序列化的过程

实例:
实现一个缓存机制(但这个只是实现了而已有很多性能问题)

  public void addGuest(Guest guest){
        String json=JSON.toJSONString(guest);
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("guest",guest);

        System.out.println(json);
        Jedis.addGuest(json);
    }
@Service
public class SerizeWithRedis {
    @Autowired
    private  GuestMapper mapper;
    public void addGuest(String json){

        //先把json放到auth里面过3秒后存到数据库,Redis自己的数据再销毁
        this.addToRedis(json);



    }

    private void addToRedis(String  json){
        Jedis jedis=new Jedis("192.168.2.163",6379);
        jedis.auth("123456");
        jedis.select(3);
        jedis.set("key1",json);
        System.out.println("成功缓存到redis");
        jedis.close();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.Rdb();
    }
    private void Rdb(){
        Jedis jedis=new Jedis("192.168.2.163",6379);
        jedis.auth("123456");
        jedis.select(3);

        String json =jedis.get("key1");
        System.out.println("Rdb"+json);
        System.out.println("key1");
        this.ParseJson(json);
        jedis.expire("key1",5);
        if(jedis.get("key1").equals("null")){
            System.out.println("持久化后东西消失");
        }

    }
    private void ParseJson(String json){

        JSONObject jsonObject=JSONObject.parseObject(json);

        Guest guest= jsonObject.toJavaObject(jsonObject,Guest.class);
        System.out.println(guest.getName());
        System.out.println(guest.getRole());
        if (guest.getName()!=null){
            mapper.addGuest(guest);
            System.out.println("将"+guest+"放到数据库了");
        }
    }
}

redis的技术栈非常丰富:
作为能和面试官大战300回合的人,Redis的数据结构需要懂得不仅仅只是String、list、Hash、set。
zset、GEO、Bitmap、Hyperloglog、Stream流、布隆过滤器这些如果能会真的在面试中很加分(挖坑+n)
系列第一期先到这期待更新吧
希望我们共同进步!!!
我是霜华一个渴望去西溪园区钓鱼的小伙子
我们下期见!!!e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值