redis五大数据类型——String
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的磁盘持久化(persistence), 并通过Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(high availability)。
String
90%的Java程序员使用redis只会使用一个string类型。
命令操作
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> exists key1
(integer) 1
127.0.0.1:6379> append key1 "hello"
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> STRLEN key1
(integer) 7
127.0.0.1:6379> APPEND key2 v2 # 如果key不存在则创建
(integer) 2
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
redis自增或自减的操作
127.0.0.1:6379> SET views 0
OK
127.0.0.1:6379> INCR views
(integer) 1
127.0.0.1:6379> GET views
"1"
127.0.0.1:6379> INCR views
(integer) 2
127.0.0.1:6379> DECR views
(integer) 1
127.0.0.1:6379> GET views
"1"
127.0.0.1:6379> INCRBY views 10 # 设置自增步长
(integer) 11
127.0.0.1:6379> DECRBY views 5 # 设置自减步长
(integer) 6
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> GETRANGE key1 1 2 # 从指定位置读取字符串
"1h"
127.0.0.1:6379> GETRANGE key1 0 -1 # 获取全部字符串
"v1hello"
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> SETRANGE key2 1 x
(integer) 7
127.0.0.1:6379> get key2
"axcdefg"
redis过期时间设置
setex(set with expire) # 设置过期时间
setnx(set if not exist) # 不存在再设置,在分布式锁中非常常用
127.0.0.1:6379> SETEX key3 30 "hello"
OK
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx key4 "redis" # 创建成功返回1
(integer) 1
127.0.0.1:6379> setnx key4 "MongoDB" # 创建失败返回0
(integer) 0
为什么说setnx在分布式锁中特别有用
- setnx key val,因为setnx当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。
- expire key timeout。为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。
- delete key删除锁
具体实现
- 使用setnx加锁,如果返回1,则说明加锁成功,并设置超时时间,避免系统一直锁住,锁没法释放。在finally中delete删除锁释放。
- 如果需要设置超时等待时间,则可以加个while循环,在获取不到锁的情况下,进行循环获取锁,超时了则退出。
mset与mestnx
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> MSETNX k1 v1 k4 v4 # 是个原子性操作
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
(integer) 0
操作对象
127.0.0.1:6379> mset user1:name zhangsan user1:age 18
OK
127.0.0.1:6379> mget user1:name user1:age
1) "zhangsan"
2) "18"
这里的key是一个巧妙的设计,user:{id}:{field},如此设计在redis中是完全没问题的。比如在微信浏览量的时候,我们就可以对这个key进行复用
127.0.0.1:6379> SET article:art_id:views 0 # 初始浏览量为0
OK
127.0.0.1:6379> INCR views
(integer) 1
127.0.0.1:6379> GET views
"1"
getset操作
# 先get然后再set
127.0.0.1:6379> GETSET db redis # 如果不存在则返回nil
(nil)
127.0.0.1:6379> GET db
"redis"
127.0.0.1:6379> GETSET db mysql
"redis"
127.0.0.1:6379> get db # 如果存在值,则返回当前值,然后设置新的值
"mysql"
记录用户调用接口次数的功能,如果实时写入数据库,性能很慢。加了一层 redis 缓存,把每分钟内的调用次数先缓存至 redis counter(每调用一次 INCR 一下)。然后有一个类似 cron 进程,会每隔一分钟读取这个计数值,一次性将次数记录到数据库中。
之前的 cron 进程是这样的:GET 读取 counter 值 -> SET 将 counter 置 0 -> 更新数据库。在流量小的情况下还很难发现问题,但是一旦流量一大,在读取 counter 和 counter 置零的之间的计数就被丢失掉了。现在只需要调用一次 GETSET 操作,确保不会有遗漏。
数据结构是相通的。
String类型的使用场景:value除了是我们的字符串,还可以是我们的数字
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
CAS
CAS是什么?
CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。
CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。