# my-redis **Repository Path**: panleiming/my-redis ## Basic Information - **Project Name**: my-redis - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-07 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # my-redis 官网地址:https://redis.io/topics/introduction 中文网站地址:http://www.redis.cn/ # 目录 1. 概念 1. SQL,NoSQL和NewSQL 2. NoSQL不同的存储类型 3. redis的特性 2. 安装 3. 基本操作 1. 库操作 2. 键操作 3. String类型操作 4. Hash类型操作 5. List类型操作 6. Set类型操作 7. ZSet类型操作 4. 存储原理 5. 问题 1. SDS是什么? 2. 为什么Redis要用SDS实现字符串? 3. embstr和raw的区别? 4. embstr什么时候会转换成raw?会还原吗? # 概念 ## SQL,NoSQL和NewSQL **关系型数据库的特点:** * 它以表格的模式,基于行存储数据,是一个二维的模式 * 存储的是结构化的数据,数据存储有固定的模式(schema),数据需要适应表结构 * 表与表之间需要存在关联 * 大部分关系型数据库都支持SQL的操作,支持复杂的关联查询 * 通过支持事务(ACID)来提供严格或者实时的数据一致性 **关系型数据库的一些限制:** * 要实现扩容的化,只能向上(垂直)扩展,比如磁盘限制了数据的存储,就要扩大磁盘容量,通过堆硬件的方式,不支持动态的扩缩容。水平扩容需要复杂的技术实现,比如分库分表 * 表结构修改困难,因此存储的数据格式也受到限制 * 在高并发高数据量的情况下,关系型数据库通常会把数据持久化到磁盘,基于磁盘的读写压力比较大 **非关系型数据库的特点:** * 存储非结构化的数据,比如文本,图片,音频,视频 * 表与表之间没有关联,可扩展性强 * 保证数据的最终一致性。遵循BASE理论。Basically Available(基本可用);Soft-state(软状态);Eventually Consistent(最终一致性) * 支持海量数据的存储和高并发的高效读写 * 支持分布式,能够对数据进行分片存储,扩缩容简单 **NewSQL则结合了SQL和NoSQL的特点** ## NoSQL不同的存储类型 * KV存储,用Key Value的形式来存储数据。比较常见的有Redis和MemcacheDB * 文档存储,MongoDB * 列存储,HBase * 图存储,Neo4j * 对象存储 * XML存储等等 更多信息可参考该网站:https://hostingdata.co.uk/nosql-database/ ## redis的特性 1. 更丰富的数据类型 2. 进程内与跨进称;单机与分布式 3. 功能丰富:持久化机制与过期策略 4. 支持多种编程语言 5. 高可用,集群 # 安装 * [单击安装]() # 基本操作 ## 库操作 默认有16个库(0-15),可以在配置文件中修改,默认使用第一个db0。因为没有完全隔离,不像数据库的database,不适合把不同的库分配给不同的业务。 切换数据库 ```java select 0 ``` 清空当前数据库 ```java flushdb ``` 清空所有数据库 ```java flushall ``` ## 键操作 Redis是字典结构的存储方式,采用key-value存储。key和value的最大长度限制在512M。 存值 ```java set age 21 ``` 取值 ```java get age ``` 查看所有键 ```java keys * ``` 获取键总数 ```java dbsize ``` 查看键是否存在 ```java exists sex ``` 删除键 ```java del sex age ``` 重命名键 ```java rename sex age ``` 查看类型 ```java type sex ``` ## String类型操作 可以用来存储字符串,整数,浮点数 设置多个值 ```java mset sex 男 age 21 ``` 设置值,如果存在key,则不成功。基于此可实现分布式锁,释放时,使用`del key`命令。 这里会有一个问题:如果释放锁失败,那么其他等待线程将永远等待,解决方法是给key加过期时间,命令为`expire key`,但这时两个命令不满足**原子性**。这里有几种方法进行替代: 1. 使用set key value \[expiration EX seconds|PX milliseconds\]\[NX|XX\],示例:`set lock 1 EX 5 NX` 2. 使用redis事务 3. 使用lua脚本 ```java setnx age 28 ``` (整数)值递增 ```java incr age incrby age 10 ``` (整数)值递减 ```java decr age decrby 10 ``` (浮点数)值增量 ```java incrbyfloat float 2.0 incrbyfloat float -0.5 ``` 获取多个值 ```java mget age sex ``` 获取值长度 ```java strlen sex ``` 字符串追加内容 ```java append age 1 ``` 获取指定范围的字符串 ```java getrange age 1 2 ``` ## Hash类型操作 设置hash值 ```java hset map name jack age 28 sex 0 hmset map1 name lili age 21 sex 1 ``` 获取hash值 ```java hget map name hmget map name age sex ``` 获取指定hash的所有field ```java hkeys map ``` 获取指定hash的所有value ```java hvals map ``` 获取指定hash的所有field-value ```java hgetall map ``` 判断指定hash的field是否存在 ```java hexists map name ``` 删除指定hash的field ```java hdel map name ``` 获取指定hash有多少个field ```java hlen map ``` 对指定hash的指定filed的值进行增加或减少 ```java hincrby map age 10 hincrby map age -10 ``` ## List类型操作 list列表是有序的,左边是列表头,从左到右 向左添加列表元素 ```java lpush list a b c ``` 向右添加列表元素 ```java rpush list d e f ``` 弹出左边元素 ```java lpop list ``` 弹出右边元素 ```java rpop list ``` 获取指定索引的元素 ```java lindex list 0 ``` 获取所有元素 ```java lrange list 0 -1 ``` ## Set类型操作 添加set元素 ```java sadd set a b c a ``` 获取set成员 ```java smembers set ``` 获取set的成员数量 ```java scard set ``` 随机获取set中的成员 ```java srandmember set 2 ``` 弹出set中的头部成员 ```java spop set ``` 删除set中指定的成员 ```java srem set a ``` 判断当前元素是否是set的成员 ```java sismember set c ``` 获取多个set集合的差集 ```java sdiff a b ``` 获取多个set集合的交集 ```java sinter a b ``` 获取多个set集合的并集 ```java sunion a b ``` ## ZSet有序集合操作 向zset有序集合中添加元素 ```java zadd myzset 1 a 2 b 3 c ``` 根据分数从小到大获取有序集合中的所有元素 ```java zrange myzset 0 -1 withscores ``` 根据分数从大到小获取有序集合中的所有元素 ```java zrevrange myzset 0 -1 withscores ``` 获取某个分数段内的元素 ```java zrangebyscore myzset 2 4 ``` 删除指定的元素 ```java zrem myzset a ``` 获取元素的数量 ```java zcard myzset ``` 新增指定元素的分数 ```java zincrby myzset 5 b ``` 获取某个分数段内的元素数量 ```java zcount myzset 2 6 ``` 返回指定元素排在第几名(按从小到大的顺序) ```java zrank myzset b ``` 返回指定元素的分数 ```java zscore myzset b ``` # 存储原理 # 问题 ## SDS是什么? Redis中字符串的实现。SDS又有多种数据结构(sds.h):sdshdr5,sdshdr8,sdshdr16,sdshdr32,sdshdr64,用于存储不同长度的字符串,分别代表2^5=32byte,2^8=256byte,2^16=65536byte=64KB,2^32=4GB ## 为什么Redis要用SDS实现字符串? C语言本身没有字符串类型(只能用字符数组char[]实现) 1. 使用字符串数组必须先给目标变量分配足够的空间,否则可能会溢出 2. 如果要获取字符串长度,必须遍历字符数组,时间复杂度是O(n) 3. C字符串长度的变更会对字符串组做重新分配 4. 通过从字符串开始到结尾碰到的第一个'\0'来标记字符串的结束,因此不能保存图片,音频,视频,压缩文件等二进制(bytes)保存的内容,二进制不安全 SDS的特点: ## embstr和raw的区别? ## embstr什么时候会转换成raw?会还原吗?