正所谓"技多不压身",好奇心满满的小安Sir在一个偶然的机会下,花了重金45块买了一个Redis课程,心想一定要好好学习,赢取白富美,走上人生巅峰!

Redis自学笔记 | 基础数据类型 (一)_java


哈哈,买了课程、买了书本就想走上人生巅峰?这不开玩笑吗?

虽说学习是性价比最高的事情了,但很容易忘记是真的,只能多写写笔记,多多实操,以求探索其中的奥秘。


顺便研究下Redis和Mysql、应用之间的联系,也想尝试下Redis是否能够和Python碰撞出不一样的火花。


下图是网友大神的提供的学习线路图,小安Sir将坚定不移地跟着这个图一步步学下去,有兴趣的小伙伴,可以点开图片,一起来玩玩哟!


红框内容为本次分享的笔记。




Redis自学笔记 | 基础数据类型 (一)_java_02


本次的笔记主要是数据类型的部分内容,本文内容较多,建议收藏阅读Redis自学笔记 | 基础数据类型 (一)_java_03


本文大纲

1.  Redis简单介绍

2.  全局通用命令

3.  字符串(String)

4.  列表(List)

5.  哈希(Hash)


01

Redis简单介绍


1.1 Redis介绍

Redis是一种基于键值对(key-value)的NoSQL数据库,与很多键值对数据库不同的是, Redis中的值可以是由string、hash、list、set(集合) 、zset 、Bitmaps、HyperLogLog、GEO等多种数据结构和算法组成。 


因此,Redis可以满足很多的应用场景,而且Redis会将所有数据都存放在内存中,所以它的读写性能非常惊人。 


不仅如此, Redis还可以将内存的数据利用快照和日志的形式保存到硬盘上,这样在发生类似断电或者机器故障的时候, 内存中的数据不会"丢失"。 除了上述功能以外, Redis还提供了键过期、 发布订阅、 事务、 流水线、 Lua脚本等附加功能。 


总之, 如果在合适的场景使用好Redis, 它就会像一把瑞士军刀一样所向披靡。


1.2 Redis使用场景

1) 缓存

2) 排行榜系统

3) 计数器应用

4) 社交网络

5) 消息队列系统


1.3 Redis的特性

1.3.1 速度快

正常情况下,Redis执行命令的速度非常快,官方给出的数字是读写性能可以达到10万/秒, 当然这也取决于机器的性能。

1) Redis是用C语言实现的,一般来说C语言实现的程序“距离”操作系统更近,执行速度相对会更快。

2) Redis使用了单线程架构, 预防了多线程可能产生的竞争问题。

3) Redis源代码可以说是精打细磨, Redis是少有的集性能和优雅于一身的开源代码。


1.3.2 基于键值对的数据结构服务器

几乎所有的编程语言都提供了类似字典的功能。主要提供了5种数据结构和其他各种神奇的"数据结构"。


1.3.3 丰富的功能

1) 提供了键过期功能, 可以用来实现缓存。

2) 提供了发布订阅功能, 可以用来实现消息系统。

3) 支持Lua脚本功能, 可以利用Lua创造出新的Redis命令。

4) 提供了简单的事务功能, 能在一定程度上保证事务特性。

5) 提供了流水线(Pipeline) 功能, 这样客户端能将一批命令一次性传到

Redis, 减少了网络的开销。


1.3.4 主从复制

Redis提供了复制功能, 实现了多个相同数据的Redis副本, 复制功能是分布式Redis的基础。 


1.3.5 高可用和分布式

Redis从3.0版本正式提供了分布式实现Redis Cluster, 它是Redis真正的分布式实现, 提供了高可用、 读写和容量的扩展性。


看完上面的内容,小安Sir已经开始摩拳擦掌了,连忙来了一套浑元形意太极拳。




02

全局通用命令


抱着学习Mysql的想法来学习Redis数据库,Mysql有DML操作,如select,update,函数如count,ddl表结构的操作,Redis也有查出所有键值,个数,键值类型的语法。


1) 查看所有键

keys *
127.0.0.1:6379> keys *
 1"fruist"
 2"name1"
 3"age"
 4"test"
 5"codehole"
 6"user-Chanson"
 7"fruits"
 8"name3"
 9"Lang"
10"name2"
11"fruits3"


2) 键总数

dbsize
127.0.0.1:6379> dbsize
(integer) 11


3)  检查键是否存在

exists key
127.0.0.1:6379exists Language
(integer) 1


4) 键的数据结构类型

type key
### 返回的类型为字符串 
127.0.0.1:6379> type age
string
### 返回的类型为hash
127.0.0.1:6379> type fruits
hash
### 返回的类型为列表
127.0.0.1:6379> type Language
list



5) 删除键

del key [key...]

注意:del是一个通用命令,无论上面数据类型,del命令都可以将其删除。

### 删除fruits(hash类型),返回值为1,说明删除成功。
127.0.0.1:6379del fruits
(integer) 1

### 再次删除fruits(hash类型),返回值为0,说明不存在。
127.0.0.1:6379del fruits

(integer) 0
### 删除字符串(字符串类型),返回值为1,说明删除成功。
127.0.0.1:6379del age
(integer) 1


6) 键过期

expire key seconds
127.0.0.1:6379> set Lang python
OK
127.0.0.1:6379> get Lang
"python"
127.0.0.1:6379> expire Lang 10
(integer) 1

ttl        :  返回键的剩余过期时间,它有3种返回值
返回值 : >=0 :键还有多少秒过期;-1:键没有设置过期时间;-2:键不存在。
127.0.0.1:6379> ttl Lang
(integer) 4            ### 键Lang 还剩下4s
127.0.0.1:6379> ttl Lang    
(integer) -2           ### 键Lang 已经不存在

### 过了5秒之后,键Lang已经没有值了
127.0.0.1:6379> get Lang
(nil)



03

字符串 (String)


3.1 字符串的相关介绍字符串 string 是 Redis 的最基本数据类型。Redis 所有的数据结构都是以唯一的 key字符串作为名称,然后通过这个唯一 key 值来获取相应的 value 数据。不同类型的数据结构的差异就在于 value 的结构不一样。另外,其他几种数据结构都是在字符串类型的基础上构建的。列表类型是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。
Redis的String类型可以是普通字符串、复杂的字符串(如Json,XML、邮箱)是二进制,意思是可以包含任何数据,比如,jpg图片,音频、视频等等。
String类型的值最大能存储512MB。

3.2 使用场景

字符串结构使用非常广泛,一个常见的用途就是缓存用户信息。我们将用户信息结构体使用 JSON 序列化成字符串,然后将序列化后的字符串塞进 Redis 来缓存。


3.3 常用命令


3.3.1 单个设置和获取

单个设置值:set key value [ex seconds] [px milliseconds] [nx|xx]  单个获取值:get key
### 创建 键值对
127.0.0.1:6379> set name Chanson
OK
### 获取键值对信息
127.0.0.1:6379> get name
"Chanson"
### 判断键值对是否存在
127.0.0.1:6379> exists name
(integer) 1
### 删除键值对
127.0.0.1:6379del name
(integer) 1

127.0.0.1:6379> get name
(nil)


3.3.2 批量设置和获取

批量设置值:mset key value [key value ...]  批量获取值:mget key [key ...]
### 通过多次set和mget的方法
127.0.0.1:6379> set name1 Hello
OK
127.0.0.1:6379> set name2 World
OK
#### 批量对多个字符串进行读写,节省网络耗时开销。
### 第一种方式
127.0.0.1:6379> mget name1 name2 name3  # 按照顺序返回
1"Hello"
2"World"
3) (nil)
127.0.0.1:6379
#### 第二种方式
### 通过mset和mget的方法
127.0.0.1:6379> mset name1 man name2 woman name3 renyao
OK
127.0.0.1:6379> mget name1 name2 name3
1"man"
2"woman"
3"renyao"


3.3.3 过期和Set命令扩展

可以对 key 设置过期时间,到点自动删除,这个功能常用来控制缓存的失效时间。 


1) setex用法
set key values [time]  等价于  setex key [time] values,单位:秒setpx 的过期时间单位:毫秒
### 普通方法
127.0.0.1:6379> set Lang python
OK
127.0.0.1:6379> get Lang
"python"
127.0.0.1:6379> expire Lang 10
(integer) 1

### setex = set + expire,Lang键10s过后过期被删除。
127.0.0.1:6379> setex Lang 10 python
OK
127.0.0.1:6379> get Lang
(nil)


2) setnx用法

set key values nx 或者 setnx key    —— key必须不存在,才可以set创建,用于添加。
### 普通方法
127.0.0.1:6379> set Lang python nx
OK
127.0.0.1:6379> get Lang
"python"

#### setnx 方法
127.0.0.1:6379> setnx Lang PHP
(integer) 1
127.0.0.1:6379> get Lang 
"PHP"

### Lang键存在,并且修改值为"python",但是失败。
127.0.0.1:6379> setnx Lang python 
(integer) 0
127.0.0.1:6379> get Lang
"PHP"


3) setxx用法

set key values xx      —— 与setnx相反,键必须存在,才可以设置成功,用于更新
### 语法明显和nx不同。
127.0.0.1:6379> setxx Lang Java 
(error) ERR unknown command `setxx`, with args beginning with: `Lang`, `Java`, 
127.0.0.1:6379> set Lang Java xx
OK
127.0.0.1:6379> get Lang
"Java"


3.3.4 计数

incr key—— incr 命令对值做自增操作,有三种返回值返回值:不是整数 :返回报错;整数:自增后的结果;键不存在:按照值为0自增,返回结果为1


如果 value 值是一个整数,还可以对它进行自增操作。自增是有范围的,它的范围是signed long 的最大最小值,超过了这个值, Redis 会报错。 

### 对于非整数自增
127.0.0.1:6379> type test
string
127.0.0.1:6379> get test
"python"
127.0.0.1:6379> incr test
(error) ERR value is not an integer or out of range
### 判断键是否存在
127.0.0.1:6379> exists age
(integer) 0
### 对一个不存在的键进行计数incr,从0开始,每次自增1
127.0.0.1:6379> incr age
(integer) 1
127.0.0.1:6379> incr age
(integer) 2
127.0.0.1:6379> incr age
(integer) 3
127.0.0.1:6379del age
(integer) 1
127.0.0.1:6379> set age 20
OK
### incr 单次增长为1
127.0.0.1:6379> incr age
(integer) 21
127.0.0.1:6379> incr age
(integer) 22
### 如果需要跨越正增长,使用incrby,但是不会连续性按指定数字增长
127.0.0.1:6379> incrby age 4
(integer) 26
127.0.0.1:6379> incr age
(integer) 27
### 如果需要跨越负增长,使用incrby,但是不会连续性按指定数字负增长
127.0.0.1:6379> incrby age -4
(integer) 23
127.0.0.1:6379> incr age
(integer) 24
... 执行多次之后
127.0.0.1:6379> incrby age -4
(integer) -8
### 设置一个 signed long 的超长数字
127.0.0.1:6379> set codehole 9223372036854775806
OK
127.0.0.1:6379> incr codehole
(integer) 9223372036854775807
127.0.0.1:6379> incr codehole
(error) ERR increment or decrement would overflow



04

列表 (List)


4.1 列表的相关介绍
4.1.1 定义

Redis列表是简单的字符串列表,用来存储多个有序的字符串,按照插入顺序排序,可以在列表的左边或者右边添加元素。

在Redis中, 可以对列表两端插入(push) 和弹出(pop) , 还可以获取指定范围的元素列表、 获取指定索引下标的元素等。


4.1.2 特点

1) 列表中的元素有序,可通过索引下标获取某个元素或者某个范围的元素列表。

2) 列表中的元素可以重复。


4.2 使用场景消息队列和文章列表等。

4.3 常用命令

4.3.1 添加操作


1) 从右边插入元素

rpush key value [value ...
### 下面代码从右向左插入元素python、 java、 golang
127.0.0.1:6379> rpush books python java golang  
(integer) 3

127.0.0.1:6379> lrange books 0 -1
1"python"
2"java"
3"golang"

127.0.0.1:6379> llen books
(integer) 3
127.0.0.1:6379> lpop books
"python"
127.0.0.1:6379> lpop books
"java"

### 列表不能GET,只能PUSH,推倒,拉扯!
127.0.0.1:6379> get books  
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> lpop books
"golang"
127.0.0.1:6379> lpop books
(nil)


2) 从左边插入元素

lpush key value [value ...]
127.0.0.1:6379> lpush books2 python java golang 
(integer) 3
127.0.0.1:6379> lrange books2 0 -1
1"golang"
2"java"
3"python"


 3) 向某个元素前或后插入元素

linsert key before|after pivot value
127.0.0.1:6379> linsert books before java SQL
(integer) 4
127.0.0.1:6379> lrange books 0 -1
1"python"
2"SQL"
3"java"
4"golang"


4.3.2 查找元素


1) 获取指定范围内的元素列表

lrange key start end  —— start 从0开始,end从-1开始。
127.0.0.1:6379> lrange books 0 2
1"python"
2"SQL"
3"java"


2) 获取指定范围内的元素列表

lindex key index
127.0.0.1:6379> lindex books 0
"python"
127.0.0.1:6379> lindex books -1
"golang"


3) 获取指定范围内的元素列表

llen key
127.0.0.1:6379> llen books
(integer) 4


4.3.3 删除元素


1) 从列表左侧弹出元素
lpop key
### 查询列表中的key
127.0.0.1:6379> lrange books 0 -1
1"python"
2"SQL"
3"java"
4"golang"

### 弹出key
127.0.0.1:6379> lpop books
"python"

127.0.0.1:6379> lrange books 0 -1
1"SQL"
2"java"
3"golang"


2) 从列表右侧弹出元素
rpop key
127.0.0.1:6379> lrange books 0 -1
1"SQL"
2"java"


3) 删除指定元素 | lrem

lrem命令会从列表中找到等于value的元素进行删除。

lrem key count value —— count分为三种情况count > 0,从左往右,最多删除count个元素;count < 0,从右往左,最多删除count(绝对值)个元素;count = 0,删除所有。
## 添加元素
127.0.0.1:6379> rpush books python
(integer) 3
127.0.0.1:6379> rpush books golang
(integer) 4
127.0.0.1:6379> lpush books golang
(integer) 5
127.0.0.1:6379> lpush books golang
(integer) 6

127.0.0.1:6379> lrange books 0 -1
1"golang"
2"golang"
3"SQL"
4"java"
5"python"
6"golang"
### 删除指定元素
127.0.0.1:6379> lrem books 2 golang
(integer) 2

127.0.0.1:6379> lrange books 0 -1
1"SQL"
2"java"
3"python"
4"golang"


4) 删除指定元素 | ltrim
ltrim key start end
127.0.0.1:6379> lrange books 0 -1
1"SQL"
2"java"
3"python"
4"golang"

### 例如, 下面操作会只保留列表listkey第2个到第3个元素:
127.0.0.1:6379> ltrim books 1 2
OK
127.0.0.1:6379> lrange books 0 -1
1"java"
2"python"


4.3.4 修改元素

修改指定索引下标的元素

lset key index newValue
127.0.0.1:6379> lrange books 0 -1
1"java"
2"python"
127.0.0.1:6379> lset books 1 PYTHON
OK
127.0.0.1:6379> lrange books 0 -1
1"java"
2"PYTHON"


05

哈希 (Hash)


5.1 Hash相关内容

几乎所有的编程语言都提供了哈希(hash)类型 。


5.1.1 优点

1) hash 结构也可以用来存储用户信息,不同于字符串一次性需要全部序列化整个对象。

2) hash 可以对用户结构中的每个字段单独存储。这样当我们需要获取用户信息时可以进行部分获取。而以整个字符串的形式去保存用户信息的话就只能一次性全部读取,这样就会比较浪费网络流量。 


5.1.2 缺点

hash 结构的存储消耗要高于单个字符串,到底该使用 hash 还是字符串,需要根据实际情况再三权衡。


5.2 使用场景

Redis hash适用于存储对象。


5.3 常用命令


1) 单个设置值和获取
hset key field value        —— 设置值hget key field              —— 获取值
### hset用法,设置值
127.0.0.1:6379> hset fruits apple "Newton's apple"
(integer) 1
127.0.0.1:6379> hset fruits peach "The Queen Mother's peach"
(integer) 1
127.0.0.1:6379> hset fruits banana "Sun WuKong's banana"
(integer) 1

### hget用法,获取值
127.0.0.1:6379> hget fruits banana
"Sun WuKong's banana"
127.0.0.1:6379> hget fruits peach
"The Queen Mother's peach"
127.0.0.1:6379> hget fruits apple
"Newton's apple"


另外一种更为直观的表达方式,user表示user表的意思,可以存放多个name值。

127.0.0.1:6379> hset user:1 name Chanson
(integer) 1
127.0.0.1:6379> hset user:2 name Tony
(integer) 1
127.0.0.1:6379> hset user:3 name Solly
(integer) 1
127.0.0.1:6379> hset user:1 age 25
(integer) 1
127.0.0.1:6379> hset user:2 age 23
(integer) 1
127.0.0.1:6379> hset user:3 age 13
(integer) 1


2) 批量设置值和获取值
hmget key filed [filed ...]        hmset key field value [field value ...]
### hmset用法 
127.0.0.1:6379> hmset fruits apple "Newton's apple" peach "The Queen Mother's peach" banana "Sun WuKong's banana"
OK

### hmget用法 
127.0.0.1:6379> hmget fruits apple peach banana
1"Newton's apple"
2"The Queen Mother's peach"
3"Sun WuKong's banana"


另外一种表达方式

127.0.0.1:6379> hmset user:4 name Jack age 28 city Hangzhou
OK
127.0.0.1:6379> hmget user:4 name age city
1"Jack"
2"28"
3"Hangzhou"

### hgetall用法,获取所有键值对
127.0.0.1:6379> hgetall fruits
1"apple"
2"Newton's apple"
3"peach"
4"The Queen Mother's peach"
5"banana"
6"Sun WuKong's banana"


3) 分别获取键、Field、值

如果hash元素个数比较多,使用hetgall时,一定要小心,因为可能会引起Redis阻塞。如果一定要获取全部的Field-Value,可以使用hscan命令,该命令会渐进式遍历哈希类型。

hexists key field         —— 确认field 是否存在hkeys key                 —— 获取所有fieldhvals  key                —— 获取所有value   hgetall key               —— 获取所有键值对
### hexists 用法,判断field是否存在
hexists user:1 name
### hgetall,获取所有field-value
127.0.0.1:6379> hgetall fruits 
1"apple"
2"Newton's apple"
3"peach"
4"The Queen Mother's peach"
5"banana"
6"Sun WuKong's banana"
127.0.0.1:6379> hgetall user:4
1"name"
2"Jack"
3"age"
4"28"
5"city"
6"Hangzhou"
### hkeys ,获取所有field
127.0.0.1:6379> hkeys fruits
1"apple"
2"peach"
3"banana"

127.0.0.1:6379> hkeys user:2
1"name"
2"age"
127.0.0.1:6379> hkeys user:4
1"name"
2"age"
3"city"
### hvals ,获取所有value
127.0.0.1:6379> hvals fruits
1"Newton's apple"
2"The Queen Mother's peach"
3"Sun WuKong's banana"

127.0.0.1:6379> hvals user:3
1"Solly"
2"13"


4) 计算Filed个数
hlen key
127.0.0.1:6379> hlen fruits
(integer) 3
127.0.0.1:6379> hlen user:1
(integer) 2
127.0.0.1:6379> hlen user:4
(integer) 3

5) 删除filed

hdel会删除一个或多个field,返回结果为成功删除的个数。

hdel key field [field...]
127.0.0.1:6379> hdel fruits apple
(integer) 1
127.0.0.1:6379> hgetall fruits
1"peach"
2"The Queen Mother's peach"
3"banana"
4"Sun WuKong's banana"

127.0.0.1:6379> hdel user:4 name 
(integer) 1
127.0.0.1:6379> hgetall user:4 
1"age"
2"28"
3"city"
4"Hangzhou"

6) hincrby 方法

同字符串一样, hash 结构中的单个子 key 也可以进行计数,它对应的指令是 hincrby,和 incr 使用基本一样。 

127.0.0.1:6379> hset user:1 age 23
(integer) 0
127.0.0.1:6379> hget user:1 age
"23"
127.0.0.1:6379> hget user:1 age
"23"
127.0.0.1:6379> hincrby user:1 age 1
(integer) 24
127.0.0.1:6379> hincrby user:1 age 2
(integer) 26
127.0.0.1:6379> hincrby user:1 age 3
(integer) 29
127.0.0.1:6379> hincrby user:1 age 4
(integer) 33


这是一个悲伤的案例,哥的岁月就这样在代码中流逝。


7) hincrbyfloat 方法

hincrby和hincrbyfloat, 就像incrby和incrbyfloat命令一样, 但是它们的作用域是filed。  

127.0.0.1:6379> hget user:1 money
"2500"
127.0.0.1:6379> hincrbyfloat user:1 money 123091.213
"125591.21300000000000097"


8) 计算value字符串的长度
hstrlen key field
127.0.0.1:6379> hstrlen user:1 name
(integer) 7
127.0.0.1:6379> hget user:1 name
"Chanson"





本次的分享就到这里结束了,下一次会把Redis数据结构的剩下的学习笔记分享出来。千里之行始于足下,Redis,小安Sir来啦!


Redis自学笔记 | 基础数据类型 (一)_java_04

学猝ing...


如果你觉得此文对你有帮助,建议收藏实操喔!如有问题,请你提出,我们可以互相一起讨论学习。


最后,非常感谢你的阅读!