Redis 入门教程——从安装到缓存实战
作者: CaoZH日期: 2024-04-15本文为原创教程
Redis 是最流行的内存数据库,2024 年 Stack Overflow 调查显示超过 40% 的开发者在使用 Redis。作为后端开发者,Redis 是缓存、会话管理、消息队列的首选方案。
本文从安装开始,涵盖 Redis 的核心数据结构和典型使用场景。
一、安装 Redis 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sudo apt update sudo apt install -y redis-server sudo systemctl start redis sudo systemctl enable redis redis-cli ping brew install redis brew services start redis
配置文件 1 2 sudo vim /etc/redis/redis.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 绑定地址(生产环境不要用 0.0.0.0) bind 127.0.0.1 # 端口 port 6379 # 密码(生产环境必须设置) requirepass yourpassword # 持久化 save 900 1 # 900秒内至少1个key改变 save 300 10 # 300秒内至少10个key改变 save 60 10000 # 60秒内至少10000个key改变 # 最大内存(设置后需要配置淘汰策略) maxmemory 256mb maxmemory-policy allkeys-lru
二、核心数据结构 String(字符串) 1 2 3 4 5 6 7 8 9 SET name "张三" GET name SET counter 100 INCR counter INCRBY counter 5 DECR counter SETEX token 3600 "abc123" TTL token
使用场景: 缓存 HTML 片段、计数器、分布式锁、Session
Hash(哈希) 1 2 3 4 5 6 7 HSET user:1001 name "张三" age 28 email "zhangsan@test.com" HGET user:1001 name HGETALL user:1001 HMSET user:1002 name "李四" age 30 HDEL user:1001 email HLEN user:1001
使用场景: 用户信息、商品详情、配置项
List(列表) 1 2 3 4 5 6 LPUSH logs "error: timeout" RPUSH logs "info: login" LPOP logs LLEN logs LRANGE logs 0 -1
使用场景: 消息队列、最新消息列表、操作日志
Set(集合) 1 2 3 4 5 6 7 SADD tags:1 "java" "python" "vue" SMEMBERS tags:1 SISMEMBER tags:1 "java" SINTER set1 set2 SUNION set1 set2 SDIFF set1 set2
使用场景: 标签系统、好友关系、权限管理
Sorted Set(有序集合) 1 2 3 4 5 6 ZADD leaderboard 100 "user1" 90 "user2" 80 "user3" ZINCRBY leaderboard 10 "user2" ZREVRANGE leaderboard 0 2 WITHSCORES ZRANK leaderboard "user2" ZSCORE leaderboard "user2"
使用场景: 排行榜、延迟队列、限流
三、Java 中使用 Redis Spring Boot 集成 1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 spring: redis: host: localhost port: 6379 password: yourpassword timeout: 3000ms lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0
RedisTemplate 使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Service public class UserService { @Autowired private RedisTemplate<String, Object> redisTemplate; public User getUserById (Long id) { String key = "user:" + id; User user = (User) redisTemplate.opsForValue().get(key); if (user != null ) { return user; } user = userMapper.selectById(id); if (user != null ) { redisTemplate.opsForValue().set(key, user, 1 , TimeUnit.HOURS); } return user; } public void updateUser (User user) { userMapper.updateById(user); redisTemplate.delete("user:" + user.getId()); } }
使用注解(@Cacheable) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Service public class ProductService { @Cacheable(value = "product", key = "#id", unless = "#result == null") public Product getById (Long id) { return productMapper.selectById(id); } @CacheEvict(value = "product", key = "#product.id") public void update (Product product) { productMapper.updateById(product); } @CacheEvict(value = "product", allEntries = true) public void clearAll () { } }
四、实战场景 1. 分布式锁 1 2 3 4 5 6 7 8 9 10 11 12 public boolean tryLock (String key, String value, long expireSeconds) { return Boolean.TRUE.equals( redisTemplate.opsForValue() .setIfAbsent(key, value, expireSeconds, TimeUnit.SECONDS) ); } public void unlock (String key, String value) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" ; redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), value); }
2. 接口限流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean rateLimit (String key, int maxCount, int windowSeconds) { String script = "" " local key = KEYS[1] local now = redis.call('TIME')[1] local window = tonumber(ARGV[1]) local max = tonumber(ARGV[2]) redis.call('ZREMRANGEBYSCORE', key, 0, now - window) local count = redis.call('ZCARD', key) if count < max then redis.call('ZADD', key, now, now .. ':' .. math.random()) redis.call('EXPIRE', key, window) return 1 end return 0 " "" ; return Long.valueOf(1 ).equals( redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), windowSeconds, maxCount) ); }
3. 缓存穿透保护 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public User getUserById (Long id) { String key = "user:" + id; Object cache = redisTemplate.opsForValue().get(key); if (cache instanceof String && "NULL" .equals(cache)) { return null ; } if (cache != null ) { return (User) cache; } User user = userMapper.selectById(id); if (user == null ) { redisTemplate.opsForValue().set(key, "NULL" , 5 , TimeUnit.MINUTES); } else { redisTemplate.opsForValue().set(key, user, 1 , TimeUnit.HOURS); } return user; }
五、常用命令速查 1 2 3 4 5 6 7 8 9 10 11 12 13 KEYS * EXISTS key TYPE key TTL key DEL key1 key2 FLUSHALL INFO MONITOR SLOWLOG GET 10 CLIENT LIST
六、总结
数据类型
使用场景
示例
✅ String
缓存、计数器、验证码
SET user:1 data
✅ Hash
对象存储
HSET user:1 name "张三"
✅ List
消息队列、最新列表
LPUSH queue task
✅ Set
标签、去重
SADD tags vue
✅ Sorted Set
排行榜、延时队列
ZADD rank 100 user1
首发于 CaoZH 的笔记