Redis使用

基本操作

General

# 返回给定模式的keys
KEYS patter
KEYS * # 返回全部
KEYS set* # 返回set开头的keys
EXISTS key
TYPE key
DEL key

String

SET key value
GET key
# Set Extend Time
SETEX key seconds value
# Set When Key Not Exist
SETNX key value

Hash

HSET key field value
HGET key field
HDEL key field
# Get All Fields
HKEYS key
# Get All Values
HVALS key
flowchart LR
key[key]
item[
field1: value1
field2: value2
]
key --> item

List

LPUSH key value1 value2
# Get Key From Start To Stop
LRANGE key start stop
# Right POP
RPOP key
# List Length
LLEN key

典型场景

订阅消息

队列,先来后到

  • 如微信、微博订阅消息
  • 阻塞队列B<L|R>POP,队列为空就等待

Set

SADD key mem1 mem2
SMEMBERS key
# Set Size
SCARD key
SINTER key1 key2
SUNION key1 key2
# Delete
SREM key mem1 mem2

典型场景

抽奖

SADD lottery {user_id}
SMEMBERS lottery
# 开奖(适用于单个奖品)
SRANDMEMBER lottery {drawing_count}
# 开奖并删除(适用于多项奖品,不重复得奖)
SPOP lottery {drawing_count}

点赞、收藏、标签

# 点赞
SADD like:{msg_id} {user_id}
# 取消
SREM like:{msg_id} {user_id}
# 用户是否点赞
SISMEMBER like:{msg_id} {user_id}
# 点赞用户列表
SMEMBERS like:{msg_id}
# 点赞用户数
SCARD like:{msg_id}

关注、商品筛选

利用集合特性运算

  • 如共同关注、推荐关注
  • 商品筛选

Sorted Set / ZSet

ZADD key score1 mem1 score2 mem2
# Show List
ZRANGE key start stop (WITHSCORES)
# Increse Member
ZINCRBY key increment member
ZREM key mem1 mem2

典型场景

日/月/年热点排行榜

# 记录浏览量
ZINCRBY hotNews:{date} 1 {news_id}
# Top 10
ZREVRANGE hotNews:{date} 0 9 WITHSCORES
# Recent 7 days
ZUNIONSTORE hotNews:{start_date}-{end_date} 0 9 WITHSCORES

Redis for Java

  • Jedis (Official Recommand)
  • Lettuce
  • Spring Data Redis

Redis Data Redis

pom.xml
<!-- Redis -->
<dependency>
<groupId>org.springframwork.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml
spring:
redis:
host: localhost
port: 6379
password: yourPassword
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
log.info("开始创建Redis模板对象...");
RedisTemplate redisTemplate = new RedisTemplate();
// Set Redis Connection Factory Object
redisTemplate.setConnectionFactory(redisConnectionFactory);
// Set Key Serializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}

持久化

RDB

# redis-cli
save
# 将会生成一个dump.rdb
bgsave
# 后台保存

AOF

保存执行的命令为日志。每次重启加载所有命令。

# redis.windows.conf
appendonly yes
appendsync always/everysec/no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# redis-cli
bgrewriteaof # 重新编排命令,让重启时执行更高效

事务

# 开始事务
multi

set key value
# ... your command
# 中途取消
discard

# 执行
exec

乐观锁

乐观锁:不认为别人会来抢占资源,所以会直接对数据进行操作,在操作时验证是否资源已被占用。

乐观锁会比较数据是否和原数据一致,一致,说明没有人抢占资源,可以修改。

watch key
# 通过版本号,而不通过值来判断
unwatch key

典型场景

对象缓存

SET user:1 <json>
MSET user:1:name the_name user1:age the_age

分布式锁

SETNX product:10003 true ex 10 nx
# success return 1, or fail return 0

... # your operation

# release the lock
DEL product:10003

计数器

INCR article:readcount:{article_id}
GET article:readcount:{article_id}

Web集群共享session

Spring Session + Redis

分布式系统全局序列号

INCRBY order_id 1000

Scan 流式遍历

SCAN cursor <KEY RegularExpression> <Count>

cursor相当于一个下标,每次查询,scan会给出下一次开始的cursor,由此实现分批查询。

Redis Lua

Lua脚本可以一次性原子地执行多条redis语句。减少网络开销、替代Redis事务。

A Redis script is transactional by defination, so everything your can do with a Redis transaction, you can also do with a script, and usually the script will be both simpler and faster.

EVAL script numkeys key [key...] arg [arg...]

numkeys: 键名参数个数
接着可以以1为基址访问keys,如KEYS[1]

$ eval "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1 key2 first second

key1
key2
first
second

Jedis使用lua脚本

jedis.set("prod_stock_10016", "15");
String script = """
local count = redis.call('get', KEYS[1])
local a = tonumber(count)
local b = tonumber(ARGV[1])
if a >= b then
redis.call('set', KEYS[1], a - b)
return 1
end
return 0
"""

Object obj = jedis.eval(script, Arrays.asList("prod_stock_10016"), Arrays.asList("10"));