📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 位图(Bitmap)
位图(Bitmap)
【简介】
Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。
【应用场景】
需要保存状态信息(0/1 即可表示)的场景
● 举例:用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
● 相关命令:SETBIT、GETBIT、BITCOUNT、BITOP。
【基本操作】
setbit key offset val:给指定key的值的第offset赋值val 时间复杂度:O(1)
getbit key offset:获取指定key的第offset位 时间复杂度:O(1)
bitcount key start end:返回指定key中[ start,end ]中为1的数量 时间复杂度:O(n)
BITPOS key bit start end:查找字符串中第一个设置为1或0的位的位置
【实战 - 文章点赞】
使用 Redis 的 Bitmaps 来处理文章的点赞功能是一个非常合适的选择,尤其是在需要高效存储和快速查询的场景中。Bitmaps 允许你以位(bit)为单位存储数据,这样可以节省存储空间并提高性能。
为什么使用 Bitmaps?
- 节省空间:每个用户的点赞状态只需要一个比特位(0 或 1),而不是存储整个用户 ID。
- 高效查询:可以快速检查某个用户是否点赞,以及统计点赞总数。
示例说明:
假设我们有一个文章 ID 为 article:123 的文章,用户 ID 为 user:456,我们可以使用 Redis 的 Bitmaps 来记录用户的点赞状态。首先,使用 Bitmap 来表示每个用户对每篇文章的点赞状态,假设文章的 ID 是 articleId,用户的 ID 是 userId,可以使用 SETBIT 命令来设置用户对文章的点赞状态。
其中:article:{articleId}:likes 作为键,用户 ID 作为偏移量。
注意事项:这里用户ID必须是数字类型。
Step1、编写业务逻辑
@Service
public class ArticleService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String LIKE_KEY_PREFIX = "article:%s:likes";
// 点赞
public void likeArticle(Long articleId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, articleId);
redisTemplate.opsForValue()
.setBit(key, userId.intValue(), true);
}
// 取消点赞
public void unlikeArticle(Long articleId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, articleId);
redisTemplate.opsForValue()
.setBit(key, userId.intValue(), false);
}
// 获取点赞数量
public Long getLikeCount(Long articleId) {
String key = String.format(LIKE_KEY_PREFIX, articleId);
Long bitCount = redisTemplate.execute((RedisCallback<Long>) connection ->
connection.bitCount(key.getBytes()), true);
return bitCount != null ? bitCount : 0;
}
// 检查用户是否点赞
public boolean hasLiked(Long articleId, Long userId) {
String key = String.format(LIKE_KEY_PREFIX, articleId);
return Boolean.TRUE.equals(redisTemplate.opsForValue()
.getBit(key, userId.intValue()));
}
}
Step2、编写控制器
@RestController
@RequestMapping("/articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
/**
* 用户点赞
* @param articleId 文章ID
* @param userId 用户ID
*/
@PostMapping("/{articleId}/like/{userId}")
public ResponseEntity<String> likeArticle(@PathVariable Long articleId, @PathVariable Long userId) {
articleService.likeArticle(articleId, userId);
return ResponseEntity.ok("OK");
}
/**
* 用户取消点赞
* @param articleId 文章ID
* @param userId 用户ID
*/
@PostMapping("/{articleId}/unlike/{userId}")
public ResponseEntity<String> unlikeArticle(@PathVariable Long articleId, @PathVariable Long userId) {
articleService.unlikeArticle(articleId, userId);
return ResponseEntity.ok("OK");
}
/**
* 获取某文章的点赞数量
* @param articleId 文章ID
*/
@GetMapping("/{articleId}/likes/count")
public ResponseEntity<Long> getLikeCount(@PathVariable Long articleId) {
Long count = articleService.getLikeCount(articleId);
return ResponseEntity.ok(count);
}
/**
* 判断用户是否点赞
* @param articleId 文章ID
* @param userId 用户ID
*/
@GetMapping("/{articleId}/like/{userId}")
public ResponseEntity<Boolean> hasLiked(@PathVariable Long articleId, @PathVariable Long userId) {
boolean hasLiked = articleService.hasLiked(articleId, userId);
return ResponseEntity.ok(hasLiked);
}
}