一、Redis基础
一、为什么要使用Redis
在实际开发中,高并发环境下,不同的用户需要相同的数据。因为每次请求,在后台我们都会创建一个线程来处理,这样造成,同样的数据从数据库里查询了N次,而数据的查询本身是IO操作,效率低,频率高也不好。
解决:将用户共享数据缓存到服务器的内存中。
特点:
1.基于键值对
2.非关系型
关系型数据库:存储了数据与数据间的关系,如oracle,mysql。
非关系型数据库:存储了数据 Redis,mdb。
3、数据存储在内存中,服务器关闭后,持久化到硬盘中。
4.支持主从同步。(从服务器和主服务器数据同步)
二、Redis命令
Set:
对不存在的键进行设置:
redis> SET key "value"
OK
redis> GET key
"value"
对已存在的键进行设置:
redis> SET key "new-value"
OK
redis> GET key
"new-value"
使用 EX 选项:
//EX seconds : 将键的过期时间设置为 seconds 秒。
redis> SET key-with-expire-time "hello" EX 10086
OK
redis> GET key-with-expire-time
"hello"
//TTL 命令以秒为单位返回 key 的剩余过期时间。
redis> TTL key-with-expire-time
(integer) 10069
使用 PX 选项:
PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。
redis> SET key-with-pexpire-time "moto" PX 123321
OK
redis> GET key-with-pexpire-time
"moto"
redis> PTTL key-with-pexpire-time
(integer) 111939
使用 NX 选项:
redis> SET not-exists-key "value" NX
OK # 键不存在,设置成功
redis> GET not-exists-key
"value"
redis> SET not-exists-key "new-value" NX
(nil) # 键已经存在,设置失败
redis> GEt not-exists-key
"value" # 维持原值不变
使用 XX 选项:
redis> EXISTS exists-key
(integer) 0
redis> SET exists-key "value" XX
(nil) # 因为键不存在,设置失败
redis> SET exists-key "value"
OK # 先给键设置一个值
redis> SET exists-key "new-value" XX
OK # 设置新值成功
redis> GET exists-key
"new-value"
三丶redis——数据结构和对象的使用介绍
1.String
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> del hello
(integer) 1
127.0.0.1:6379> get hello
(nil)
127.0.0.1:6379>
应用场景
String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String,也可以是数字:比如想知道什么时候封锁一个IP地址(访问超过几次)。INCRBY命令让这些变得很容易,通过原子递增保持计数。
2.List
// 获取列表所有元素
lrange list 0 -1
//获取部分元素
lrange list 0 2
//区间为[0,2]闭区间
//在第一个元素前添加:lpush
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
//在最后一个元素后添加:rpush
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> rpush list four
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
//移除首元素:lpop
//移除末尾元素:rpop
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpop list
"one"
//移除后都会返回移除的值。
//通过数据值移除:lrem
//格式: lrem 列表名 删除数量 元素值
//删除一条数据:
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
3) "one"
//删除多条数据:
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "three"
4) "four"
5) "two"
6) "one"
127.0.0.1:6379> lrem list 2 three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "four"
3) "two"
4) "one"
返回删除的数量。
//获取列表长度
llen list
//通过index获取数据,获取index=0的数据
lindex list 0
//截取列表
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "four"
3) "two"
4) "one"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
//ltrim区间在[1,2],截取以后只剩下截取的元素。
//元素替换,若不存在会报错。
127.0.0.1:6379> lrange list 0 0
1) "one"
127.0.0.1:6379> lset list 0 item
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
//插入元素
127.0.0.1:6379> lrange list 0 -1
1) "item"
2) "two"
3) "three"
127.0.0.1:6379> linsert list before two vlaue233
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "item"
2) "vlaue233"
3) "two"
4) "three"
127.0.0.1:6379> linsert list after two vlaueAfter
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "item"
2) "vlaue233"
3) "two"
4) "vlaueAfter"
5) "three"
//linsert 列表名 before|after 已存在元素 要插入的元素
应用场景
Redis list的应用场景非常多,也是Redis最重要的数据结构之一。
我们可以轻松地实现最新消息排行等功能。
Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。
3.Hash
Redis Hset 命令用于为哈希表中的字段赋值 。
如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
如果字段已经存在于哈希表中,旧值将被覆盖。
redis 127.0.0.1:6379> HSET myhash field1 "foo"
OK
redis 127.0.0.1:6379> HGET myhash field1
"foo"
redis 127.0.0.1:6379> HSET website google "www.g.cn" # 设置一个新域
(integer) 1
redis 127.0.0.1:6379>HSET website google "www.google.com" # 覆盖一个旧域
(integer) 0
> hset hash-key sub-key1 value1
(integer) 1
> hset hash-key sub-key2 value2
(integer) 1
> hset hash-key sub-key1 value1
(integer) 0
> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
> hdel hash-key sub-key2
(integer) 1
> hdel hash-key sub-key2
(integer) 0
> hget hash-key sub-key1
"value1"
> hgetall hash-key
1) "sub-key1"
2) "value1"
4.Set
> sadd set-key item
(integer) 1
> sadd set-key item2
(integer) 1
> sadd set-key item3
(integer) 1
> sadd set-key item
(integer) 0
> smembers set-key
1) "item2"
2) "item"
3) "item3"
> sismember set-key item4
(integer) 0
> sismember set-key item
(integer) 1
> srem set-key item
(integer) 1
> srem set-key item
(integer) 0
> smembers set-key
1) "item2"
2) "item3"
5.ZSET
> zadd zset-key 728 member1
(integer) 1
> zadd zset-key 982 member0
(integer) 1
> zadd zset-key 982 member0
(integer) 0
> zrange zset-key 0 -1
1) "member1"
2) "member0"
> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
> zrem zset-key member1
(integer) 1
> zrem zset-key member1
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"
四、数据库相关
1.键空间
键空间的键也就是数据库的键, 每个键都是一个字符串对象。
键空间的值也就是数据库的值, 每个值可以是字符串对象、列表对象、哈希表对象、集合对象、有序集合对象。
2.维护
读写键空间的时候,服务器会执行一些额外操作,比如:
- 读一个键后(读操作写操作都要对键读取), 会根据键是否存在, 更新键空间命中(hit)次数或不命中(miss)次数。
- 读取一个键后, 服务器会更新键的 LRU (最后一次使用)时间, 这个值可以用于计算键的闲置时间。
- 如果服务器在读一个键时, 该键已经过期, 服务器会删除这个键, 然后执行其他操作。
- 如果客户使用 WATCH 监视某个键,在对这个键进行修改之后, 会将这个键记为脏(dirty),让事务程序知到这个键被修改
- 服务器每次修改一个键之后, 都会对脏(dirty)键计数器的值增一, 这个计数器会触发服务器的持久化以及复制操作执行
- 如果服务器开启了数据库通知功能, 那么在对键进行修改之后, 服务器将按配置发送相应的数据库通知。
3.时间
用户可以给某个键设置生存时间,过期时间是一个unix时间戳,到时间自动删除这个键,redisdb结构的expires字典保存了所有键的过期时间,我们称这个字典为过期字典。
4. 三种过期键策略
- 定时策略:创建一个定时器,到期立即执行删除操作(对内存友好,能保证过期了立马删除,但是对cpu不友好)
- 惰性删除:键过期不管,每次获取键时检查是否过期,过期就删除(对cpu友好,但是只有在使用的时候才有可能删除,对内存不友好)
- 定期删除:隔一段时间检查一次