Review

Review

redis

1.基于内存的高性能的k-v非关系型数据库。

2.常用的基本类型 string set zset map list (bitmap,布隆过滤器)

3常用指令 :

​ 1 String :

​ set k v 存储一个key为k ,value 的值,成功返回ok;

​ get k 获取一个 key为k 的值,存在返回值,否则返回nil 空值

 set name cxx
    get name
    getrange name 0 -1        字符串分段
    getset name new_cxx       设置值,返回旧值
    mset key1 key2            批量设置
    mget key1 key2            批量获取
    setnx key value           不存在就插入(not exists)
    setex key time value      过期时间(expire)
    setrange key index value  从index开始替换value
    incr age        递增
    incrby age 10   递增
    decr age        递减
    decrby age 10   递减
    incrbyfloat     增减浮点数
    append          追加
    strlen          长度
    getbit/setbit/bitcount/bitop    位操作

​ 2 list :

 lpush mylist a b c  左插入
    rpush mylist x y z  右插入
    lrange mylist 0 -1  数据集合
    lpop mylist  弹出元素
    rpop mylist  弹出元素
    llen mylist  长度
    lrem mylist count value  删除
    lindex mylist 2          指定索引的值
    lset mylist 2 n          索引设值
    ltrim mylist 0 4         删除key
    linsert mylist before a  插入
    linsert mylist after a   插入
    rpoplpush list list2     转移列表的数据

​ 3 set:

  sadd myset redis 
    smembers myset       数据集合
    srem myset set1         删除
    sismember myset set1 判断元素是否在集合中
    scard key_name       个数
    sdiff | sinter | sunion 操作:集合间运算:差集 | 交集 | 并集
    srandmember          随机获取集合中的元素
    spop                 从集合中弹出一个元素

​ 4 zset:

  zadd zset 1 one
    zadd zset 2 two
    zadd zset 3 three
    zincrby zset 1 one              增长分数
    zscore zset two                 获取分数
    zrange zset 0 -1 withscores     范围值
    zrangebyscore zset 10 25 withscores 指定范围的值
    zrangebyscore zset 10 25 withscores limit 1 2 分页
    Zrevrangebyscore zset 10 25 withscores  指定范围的值
    zcard zset  元素数量
    Zcount zset 获得指定分数范围内的元素个数
    Zrem zset one two        删除一个或多个元素
    Zremrangebyrank zset 0 1  按照排名范围删除元素
    Zremrangebyscore zset 0 1 按照分数范围删除元素
    Zrank zset 0 -1    分数最小的元素排名为0
    Zrevrank zset 0 -1  分数最大的元素排名为0
    Zinterstore
    zunionstore rank:last_week 7 rank:20150323 rank:20150324 rank:20150325  weights 1 1 1 1 1 1 1

​ 5 map :

 hset myhash name cxx
    hget myhash name
    hmset myhash name cxx age 25 note "i am notes"
    hmget myhash name age note   
    hgetall myhash               获取所有的
    hexists myhash name          是否存在
    hsetnx myhash score 100      设置不存在的
    hincrby myhash id 1          递增
    hdel myhash name             删除
    hkeys myhash                 只取key
    hvals myhash                 只取value
    hlen myhash                  长度

4.下载安装

官网下载.gz文件 通过tar -zxvf xxxx.gz 进行解压

下载安装gcc,c++,用于redis的编译

yum install gcc-c++

cd 到解压好的文件夹下面,先make 再进入文件夹下的src 进行make install,

修改redis.conf中的内容,设置绑定ip,或者注释

protected-mode 改为 no

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FhQu4vp-1600735919273)(C:\Users\15270\AppData\Roaming\Typora\typora-user-images\image-20200910095409721.png)]

设置在后台运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kmn08OmU-1600735919275)(C:\Users\15270\AppData\Roaming\Typora\typora-user-images\image-20200910095543008.png)]

设置密码 在requirepass中设置 为 123456

5其他知识

默认有16个数据库,通过select 0-15 来选择不同的数据库

可以选择不同的库来存储不同类型的数据

dbsize 通过db 和TAB补全,来查看有几个key

通过keys * 来查看使用元素的value

默认索引是从0开始 flushdb 清除当前库的数据,flushdb清除所有

6 key 关键字

move k num 把key为k的值移到num号库

expire key 秒 设置可以的过期时间

ttl key 还有多少秒过期 -1 永不过期 -2 过期

type key key的类型

exist key 是否存在key

7持久化rdb redisdatabase

指定时间间隔内将数据快照写入指定文件dump.rdb,

通过一个fork线程来进行持久化,每次将数据写到临时文件,然后替代原文件。rdb文件最后一次持久化数据可能会丢失。

保存方式

Save the DB on disk:

save

多少秒内多少次操作保存

默认:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0YYAyGiJ-1600735919276)(C:\Users\15270\AppData\Roaming\Typora\typora-user-images\image-20200910115238981.png)]

900s 1次 300s 10次 60s 1000次

save 可以迅速备份

在dir 中可以修改文件保存目录

8持久化aof append only File

以日志方式记录写操作

默认不开启 appendonly yes 修改为开启

rdb和aof同事存在默认加载aof

aof出现语法错误redis可能无法启动可以做到修复aof文件

redis-check-aof 修复aof文件

appendfsync always 同步持久化 everysec 每秒同步,会有一秒数据丢失(mr)

会重写,大小超过阀值,只保留可以恢复最小指令值

默认大小是上次rewrite后一倍切大于64m重写

9事务

一连串操作,串行化操作,其中有一个失败,数据不会回滚,成功的都成功,失败的失败。(语法错误会导致操作失败

mutil创建事务 每次操作都会入队

xxx xxx操作

exec 执行

watch 监控一个key 先监控在开启事务挡在监控过程中可以被改变了事务就会失败。

unwatch放弃监控

10.Redis 的主从复制

持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障

11.布隆过滤器

通过hash算法算出一个数据的值,并用bitmap在其中设置,吧0改为一,下次要查找的时候只要通过hash查看对应位置上的值是否为1来判断是否存在该值

12 bitmap

setbit k1 offest value

setbit k1 1 1

0100 0000

设置一个长度为一位的字节,偏移量为1,值为1

ArrayList

内部为一个数组,构造方法不加参数初始大小为10,

每次扩容为原来大小的一半,查询效率很快,添加和删除效率低。

空参数构造方法

/**
 * Constructs an empty list with an initial capacity of ten.
 // 空参数构造方法,elementData赋予一个默认空数组
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
// 有参构造方法,传入数值为0 也是空数组
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

add方法,第一次添加的时候才会初始化数组大小,

每次添加都会检查数组size大小

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!再其中确认,并扩容和复制数组,数组大小,通过size+1 来判断size会不会超过数组大小
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 如果数组为默认空数组,数组大小为传入大小和10的较大的那一个,一般为10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
// 明确数组的容量
    ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++; // 改变次数加1

    // overflow-conscious code
    如果参入容量大于原数组长度,扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 新容量为原来容量+原容量右移1位
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 第一次初始化新容量为0,所以容量改为10;
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        // 新容量大于最大规定值inegere_max -8;
        就再次变大;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 通过Arrays。copy复制数组到新容量数组
    elementData = Arrays.copyOf(elementData, newCapacity);

流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tw6Zxb8S-1600735919278)(C:\Users\15270\AppData\Roaming\Typora\typora-user-images\image-20200910160815282.png)]

删除

public E remove(int index) {
// 边界检查
    rangeCheck(index);

    modCount++;
    // 获得指定要删除元素
    E oldValue = elementData(index);
	// 数组要移动的数量
    int numMoved = size - index - 1;
    if (numMoved > 0)
    // 数组复制移动
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
                         // size-1最后一位变为null
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

HashMap

1.8 通过数组建表,链表到达一定长度后转化为红黑树来实现

重要参数

默认初始容量大小,空参数
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
默认最大size
static final int MAXIMUM_CAPACITY = 1 << 30;
// 默认扩容的负载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 树的最小链表长的
static final int TREEIFY_THRESHOLD = 8;
// 树结构变为链表的最小长度
static final int UNTREEIFY_THRESHOLD = 6;
// 可以树化的最小元素个数
static final int MIN_TREEIFY_CAPACITY = 64;

空参数构造方法

/**
 * Constructs an empty <tt>HashMap</tt> with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
负载因子变为0.75
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

总共四个构造方法,参数有初始容量,负载因子和一个map结构

map的put方法

流程,

把key进行hash,找出对应的数组下表,并放进去有值就通过链表方式放进去,链表长度和map元素个数到达一定的值,链表转化为红黑树。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

主要方法putVal,把key重新进行hash算法

static final int hash(Object key) {
    int h;
    // key的hashcode和还是从的右移16位进行异或运算,获得行的hash
   避免hash碰撞,希望key在数组均匀分布
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
               // tab临时变量
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // 第一次table为空 ,n为临时数组大小进行扩容。
    if ((tab = table) == null || (n = tab.length) == 0)
    // 第一次n为16
        n = (tab = resize()).length;
        // 确定节点要插入的位置
        数组下表为数组长度-1和hash的与运算,为空就插入新节点
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
        // 否则p的hash和hash是否相同,p的可以和key是否相同,如果是临时节点e=p
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
            // p为树形节点,树形插入
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
        // 在链表上循环,找到相同的key返回e=跑,否则创建新的节点返回,假如数量超过8,树化
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        // e不为空,说明链表上有key相同的,value接替代原来的返回
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    // size>当前容量x负载因子,扩容
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

扩容

/**
 * Initializes or doubles table size.  If null, allocates in
 * accord with initial capacity target held in field threshold.
 * Otherwise, because we are using power-of-two expansion, the
 * elements from each bin must either stay at same index, or move
 * with a power of two offset in the new table.
 *
 * @return the table
 */
final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;//老的table
    int oldCap = (oldTab == null) ? 0 : oldTab.length;// 原容量,原数组为空就是0
    // 原需要扩容的大小
    int oldThr = threshold;
   // 行的容量和需要扩容的大小
    int newCap, newThr = 0;
    // 原容量大于0,大于最大容量,需要扩容的大小变为integer_max
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        // 新容量为原来容量的一倍,并且小于最大默认容量,小于默认容量
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
                 // 需要扩容的值也左移一位
            newThr = oldThr << 1; // double threshold
    }
    // 旧容量大于0,
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {               // zero initial threshold signifies using defaults
    // 初始化容量和扩容大小
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    // 通过负载因子和初始容量参数构造
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
    // 原来table有值复制进去
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                oldTab[j] = null;
                if (e.next == null)
                // e没有next
                // e的hash和新容量-1与运算加到新数组
                    newTab[e.hash & (newCap - 1)] = e;			// 如果数数状,就树形加载
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { // preserve order
                //链表插入新数组,通过e.hash和oldcap与运算,区分节点在新组数上边部分还是下半部分。
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        else {
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

返回当前数比它大的2的倍数

红黑树

1,根节点为黑色

2,每一个节点到末尾的黑节点数量相同,黑色平衡

3,不能有连续的红色节点

4,查询效率logn

5,插入节点为红色节点

节点的插入

1,空树,插入红色节点,变成黑色。

2,插入节点的父亲节点为黑色,不做其他操作

3,插入节点的父亲节点为红色

​ 3.1,有叔叔节点为红色,父亲和叔叔变红,插入变黑,以祖父节点为当前节点再次变色

​ 3.1有叔叔节点为黑色或者没有叔叔节点

​ a,插入节点父节点为祖父节点左节点,自己为左节点,以父亲节点右旋,变色。自己右边节点,以自己左旋,再以父亲右旋变色

​ b。插入节点父亲节点为右子节点,自己是右节点,以父亲节点左旋变色,自己为左节点,以自己右旋,再以父亲左旋变色。父亲变黑色,祖父变红色

旋转,

左旋,当前节点变成父亲节点,原父亲节点变成变成当前节点左子节点

n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}


返回当前数比它大的2的倍数

# 红黑树

1,根节点为黑色

2,每一个节点到末尾的黑节点数量相同,黑色平衡

3,不能有连续的红色节点

4,查询效率logn

5,插入节点为红色节点

节点的插入

1,空树,插入红色节点,变成黑色。

2,插入节点的父亲节点为黑色,不做其他操作

3,插入节点的父亲节点为红色

​	3.1,有叔叔节点为红色,父亲和叔叔变红,插入变黑,以祖父节点为当前节点再次变色

​	3.1有叔叔节点为黑色或者没有叔叔节点

​		a,插入节点父节点为祖父节点左节点,自己为左节点,以父亲节点右旋,变色。自己右边节点,以自己左旋,再以父亲右旋变色

​		b。插入节点父亲节点为右子节点,自己是右节点,以父亲节点左旋变色,自己为左节点,以自己右旋,再以父亲左旋变色。父亲变黑色,祖父变红色

旋转,

左旋,当前节点变成父亲节点,原父亲节点变成变成当前节点左子节点

右旋,当前节点变成父亲节点,原父亲节点变成其右子节点。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值