编辑
2025-01-28
缓存
00
请注意,本文编写于 159 天前,最后修改于 10 天前,其中某些信息可能已经过时。

目录

Redis数据类型深度解析
目录
1. String(字符串)
1.1 数据结构图
1.2 原理讲解
1.3 应用场景
1.4 SpringBoot集成示例
2. List(列表)
2.1 数据结构图
2.2 原理讲解
2.3 应用场景
2.4 SpringBoot集成示例
3. Hash(哈希)
3.1 数据结构图
3.2 原理讲解
3.3 应用场景
3.4 SpringBoot集成示例
4. Set(集合)
4.1 数据结构图
4.2 原理讲解
4.3 应用场景
4.4 SpringBoot集成示例
5. Sorted Set(有序集合)
5.1 数据结构图
5.2 原理讲解
5.3 应用场景
5.4 SpringBoot集成示例
6. Bitmap(位图)
6.1 数据结构图
6.2 原理讲解
6.3 应用场景
6.4 SpringBoot集成示例
7. HyperLogLog(基数统计)
7.1 数据结构图
7.2 原理讲解
7.3 应用场景
7.4 SpringBoot集成示例
8. GEO(地理位置)
8.1 数据结构图
8.2 原理讲解
8.3 应用场景
8.4 SpringBoot集成示例
总结

Redis数据类型深度解析

目录

1. String(字符串)

1.1 数据结构图

+-------------------+ | "Hello World" | +-------------------+

1.2 原理讲解

String是Redis最基本的数据类型,一个key对应一个value。String类型是二进制安全的,意味着Redis的String可以包含任何数据,比如jpg图片或者序列化的对象。String类型的值最大能存储512MB。

1.3 应用场景

  1. 缓存功能:最常用的缓存字符串,对象序列化后存储
  2. 计数器:利用INCR、DECR等命令实现原子性的计数操作
  3. 分布式锁:使用SETNX命令实现分布式锁机制

1.4 SpringBoot集成示例

java
@Service public class StringCacheService { @Autowired private StringRedisTemplate redisTemplate; // 缓存用户信息 public void cacheUser(String userId, String userInfo) { String key = "user:info:" + userId; redisTemplate.opsForValue().set(key, userInfo, Duration.ofHours(1)); } // 获取用户信息 public String getUserInfo(String userId) { String key = "user:info:" + userId; return redisTemplate.opsForValue().get(key); } // 计数器功能 public Long incrementCounter(String counterKey) { return redisTemplate.opsForValue().increment(counterKey); } // 分布式锁 public boolean tryLock(String lockKey, String lockValue, Duration expireTime) { return Boolean.TRUE.equals( redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expireTime) ); } }

2. List(列表)

2.1 数据结构图

+-------+-------+-------+-------+ | "A" | "B" | "C" | "D" | +-------+-------+-------+-------+ 0 1 2 3 索引

2.2 原理讲解

List是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。List的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

2.3 应用场景

  1. 消息队列:利用LPUSH和RPOP实现简单的消息队列
  2. 最新动态列表:存储用户最新的动态信息,如微博时间线
  3. 任务队列:实现异步任务处理队列

2.4 SpringBoot集成示例

java
@Service public class ListQueueService { @Autowired private StringRedisTemplate redisTemplate; // 添加消息到队列 public void pushMessage(String queueKey, String message) { redisTemplate.opsForList().leftPush(queueKey, message); } // 从队列获取消息 public String popMessage(String queueKey) { return redisTemplate.opsForList().rightPop(queueKey); } // 获取最新动态列表 public List<String> getLatestFeeds(String userId, int count) { String key = "user:feeds:" + userId; return redisTemplate.opsForList().range(key, 0, count - 1); } // 添加用户动态 public void addUserFeed(String userId, String feed) { String key = "user:feeds:" + userId; redisTemplate.opsForList().leftPush(key, feed); // 保持列表长度不超过100 redisTemplate.opsForList().trim(key, 0, 99); } }

3. Hash(哈希)

3.1 数据结构图

+----------+----------+ | Field | Value | +----------+----------+ | name | "张三" | | age | "25" | | city | "北京" | +----------+----------+

3.2 原理讲解

Hash是一个键值对集合,是一个String类型的field和value的映射表。Hash特别适合用于存储对象。每个Hash可以存储2^32-1键值对(40多亿)。

3.3 应用场景

  1. 用户信息存储:存储用户的详细信息,避免序列化开销
  2. 购物车功能:存储用户购物车中的商品信息
  3. 配置信息管理:存储系统配置参数

3.4 SpringBoot集成示例

java
@Service public class HashUserService { @Autowired private StringRedisTemplate redisTemplate; // 存储用户信息 public void saveUserInfo(String userId, Map<String, String> userInfo) { String key = "user:profile:" + userId; redisTemplate.opsForHash().putAll(key, userInfo); } // 获取用户信息 public Map<Object, Object> getUserInfo(String userId) { String key = "user:profile:" + userId; return redisTemplate.opsForHash().entries(key); } // 更新用户单个字段 public void updateUserField(String userId, String field, String value) { String key = "user:profile:" + userId; redisTemplate.opsForHash().put(key, field, value); } // 购物车操作 public void addToCart(String userId, String productId, String quantity) { String key = "cart:" + userId; redisTemplate.opsForHash().put(key, productId, quantity); } // 获取购物车内容 public Map<Object, Object> getCartItems(String userId) { String key = "cart:" + userId; return redisTemplate.opsForHash().entries(key); } }

4. Set(集合)

4.1 数据结构图

+-------------------+ | { "A", "B", "C" } | +-------------------+

4.2 原理讲解

Set是String类型的无序集合。集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。Set中的元素是唯一的,不允许重复。

4.3 应用场景

  1. 标签系统:存储文章或用户的标签信息
  2. 好友关系:存储用户的好友列表,支持交集、并集操作
  3. 去重功能:利用Set的唯一性实现数据去重

4.4 SpringBoot集成示例

java
@Service public class SetTagService { @Autowired private StringRedisTemplate redisTemplate; // 为文章添加标签 public void addArticleTags(String articleId, String... tags) { String key = "article:tags:" + articleId; redisTemplate.opsForSet().add(key, tags); } // 获取文章标签 public Set<String> getArticleTags(String articleId) { String key = "article:tags:" + articleId; return redisTemplate.opsForSet().members(key); } // 添加好友关系 public void addFriend(String userId, String friendId) { String key = "user:friends:" + userId; redisTemplate.opsForSet().add(key, friendId); } // 获取共同好友 public Set<String> getCommonFriends(String userId1, String userId2) { String key1 = "user:friends:" + userId1; String key2 = "user:friends:" + userId2; return redisTemplate.opsForSet().intersect(key1, key2); } // 数据去重 public void addUniqueVisitor(String pageId, String visitorId) { String key = "page:visitors:" + pageId; redisTemplate.opsForSet().add(key, visitorId); } }

5. Sorted Set(有序集合)

5.1 数据结构图

+-------+-------+ | Score | Value | +-------+-------+ | 100 | "张三" | | 95 | "李四" | | 90 | "王五" | +-------+-------+

5.2 原理讲解

Sorted Set是Set的一个升级版本,它在Set的基础上增加了一个顺序属性score,这一属性在添加修改元素的时候可以指定。每次指定后,Sorted Set会自动重新按新的值调整顺序。

5.3 应用场景

  1. 排行榜系统:游戏积分排行榜、销售排行榜等
  2. 延时队列:使用时间戳作为score实现延时任务
  3. 优先级队列:根据优先级处理任务

5.4 SpringBoot集成示例

java
@Service public class SortedSetRankService { @Autowired private StringRedisTemplate redisTemplate; // 更新用户积分 public void updateUserScore(String userId, double score) { String key = "game:leaderboard"; redisTemplate.opsForZSet().add(key, userId, score); } // 获取排行榜前N名 public Set<ZSetOperations.TypedTuple<String>> getTopPlayers(int count) { String key = "game:leaderboard"; return redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, count - 1); } // 获取用户排名 public Long getUserRank(String userId) { String key = "game:leaderboard"; return redisTemplate.opsForZSet().reverseRank(key, userId); } // 延时任务队列 public void addDelayedTask(String taskId, long executeTime) { String key = "delayed:tasks"; redisTemplate.opsForZSet().add(key, taskId, executeTime); } // 获取到期任务 public Set<String> getExpiredTasks(long currentTime) { String key = "delayed:tasks"; return redisTemplate.opsForZSet().rangeByScore(key, 0, currentTime); } }

6. Bitmap(位图)

6.1 数据结构图

+---+---+---+---+---+---+---+---+ | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | +---+---+---+---+---+---+---+---+ 0 1 2 3 4 5 6 7 位置

6.2 原理讲解

Bitmap不是一个实际的数据类型,而是基于String类型的位操作。在Redis中,String类型的值最大可以是512MB,即可以存储多达2^32个不同的位。每个位只能存储0或1两种状态,非常适合存储布尔类型的数据。

6.3 应用场景

  1. 用户签到记录:记录用户每日签到状态
  2. 在线状态统计:统计用户在线状态
  3. 权限控制:判断用户是否具有某项权限

6.4 SpringBoot集成示例

java
@Service public class UserSignService { @Autowired private StringRedisTemplate redisTemplate; // 用户签到 public void userSign(String userId, LocalDate date) { String key = "user:sign:" + userId + ":" + date.getYear() + ":" + date.getMonthValue(); redisTemplate.opsForValue().setBit(key, date.getDayOfMonth() - 1, true); } // 检查用户是否签到 public boolean checkSign(String userId, LocalDate date) { String key = "user:sign:" + userId + ":" + date.getYear() + ":" + date.getMonthValue(); return Boolean.TRUE.equals(redisTemplate.opsForValue().getBit(key, date.getDayOfMonth() - 1)); } }

7. HyperLogLog(基数统计)

7.1 数据结构图

+----------------+ | Register 1 | +----------------+ | Register 2 | +----------------+ | ... | +----------------+ | Register 16384| +----------------+

7.2 原理讲解

HyperLogLog是一种用于基数统计的概率性数据结构,可以在使用固定且很小的内存空间(每个HyperLogLog键只需要花费12KB内存)的情况下,计算集合中不重复元素的数量。其原理基于概率学中的伯努利试验,通过观察集合元素的二进制表示中前导零的数量来估算基数。

7.3 应用场景

  1. 网站UV统计:统计网站独立访客数量
  2. APP日活统计:统计应用程序日活跃用户数
  3. 搜索热词统计:统计用户搜索的不重复关键词数量

7.4 SpringBoot集成示例

java
@Service public class UVCountService { @Autowired private StringRedisTemplate redisTemplate; // 记录用户访问 public void recordUserVisit(String userId, LocalDate date) { String key = "uv:" + date; redisTemplate.opsForHyperLogLog().add(key, userId); } // 获取当日UV public long getUVCount(LocalDate date) { String key = "uv:" + date; return redisTemplate.opsForHyperLogLog().size(key); } // 获取指定时间范围内的UV public long getUVCountInRange(LocalDate startDate, LocalDate endDate) { String destKey = "uv:range:" + startDate + ":" + endDate; String[] keys = new String[(int) ChronoUnit.DAYS.between(startDate, endDate) + 1]; int index = 0; for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) { keys[index++] = "uv:" + date; } redisTemplate.opsForHyperLogLog().union(destKey, keys); return redisTemplate.opsForHyperLogLog().size(destKey); } }

8. GEO(地理位置)

8.1 数据结构图

+-------------+-------------+----------+ | 经度 | 纬度 | 成员 | +-------------+-------------+----------+ | 116.397128 | 39.916527 | 商家A | | 116.321429 | 39.897308 | 商家B | | 116.380338 | 39.913527 | 商家C | +-------------+-------------+----------+

8.2 原理讲解

GEO(Geospatial)是Redis用于存储地理位置信息的数据类型,其底层实际上是基于Sorted Set实现的。Redis会将二维的经纬度转换成一维的52位整数(GeoHash编码),并将这个整数作为Sorted Set的score值。这种设计让我们可以方便地进行范围查找和距离计算。

8.3 应用场景

  1. LBS服务:附近的人/店铺查询功能
  2. 智能派单:打车软件的司机派单系统
  3. 配送优化:外卖配送距离计算和路径优化

8.4 SpringBoot集成示例

java
@Service public class LocationService { @Autowired private StringRedisTemplate redisTemplate; // 添加商家位置 public void addShopLocation(String shopId, double longitude, double latitude) { String key = "shop:locations"; redisTemplate.opsForGeo().add(key, new Point(longitude, latitude), shopId); } // 查找附近的商家 public List<GeoResult<RedisGeoCommands.GeoLocation<String>>> findNearbyShops( double longitude, double latitude, double radius) { String key = "shop:locations"; Circle circle = new Circle(new Point(longitude, latitude), new Distance(radius, Metrics.KILOMETERS)); GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo() .search(key, circle); return results.getContent(); } // 计算两个商家之间的距离 public Distance getDistance(String shopId1, String shopId2) { String key = "shop:locations"; return redisTemplate.opsForGeo() .distance(key, shopId1, shopId2, Metrics.KILOMETERS); } }

总结

本文详细介绍了Redis中八种重要的数据类型,包括五种基本数据类型和三种高级数据类型。每种数据类型都有其独特的特性和适用场景:

基本数据类型:

  • String:最基础的键值存储,适用于缓存、计数器、分布式锁等场景
  • List:有序列表结构,适用于消息队列、时间线、任务队列等场景
  • Hash:键值对映射表,适用于对象存储、购物车、配置管理等场景
  • Set:无序唯一集合,适用于标签系统、好友关系、数据去重等场景
  • Sorted Set:有序集合,适用于排行榜、延时队列、优先级队列等场景

高级数据类型:

  • Bitmap:位图操作,适用于用户签到、状态统计、权限控制等场景
  • HyperLogLog:基数统计,适用于UV统计、日活统计、热词统计等场景
  • GEO:地理位置,适用于LBS服务、智能派单、配送优化等场景

在实际应用中,合理选择和使用这些数据类型不仅能提高系统性能,还能大大降低内存使用量和开发复杂度。通过SpringBoot的集成示例,我们可以看到这些数据类型在实际项目中的应用方式都相对简单直观。掌握这些数据类型的特性和使用场景,对于构建高性能、可扩展的Redis应用至关重要。

本文作者:大哥吕

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!