当前位置: 首页 > wzjs >正文

记事本做网站如何添加图片爱射影院网站建设中

记事本做网站如何添加图片,爱射影院网站建设中,投资公司注册需要什么资质,做网站的公司 贵阳前言 为什么所用 redis 作为缓存来实现点赞服务, 而不是直接就使用 mysql 来完成? 使用 Redis 的集合数据结构来存储点赞用户的 ID,方便快速判断用户是否已点赞; 当用户频繁的点赞和取消点赞时, 无需操作数据库, 减轻服务器压力 Redis 可以承受高并发的读写操作…

前言

为什么所用 redis 作为缓存来实现点赞服务, 而不是直接就使用 mysql 来完成?

  1. 使用 Redis 的集合数据结构来存储点赞用户的 ID,方便快速判断用户是否已点赞;

  2. 当用户频繁的点赞和取消点赞时, 无需操作数据库, 减轻服务器压力

  3. Redis 可以承受高并发的读写操作。当大量用户同时点赞时,Redis 可以先将这些点赞请求缓存起来,然后由后台线程逐步将数据持久化到 MySQL

实现

查询流程

客户端
API Gateway
点赞服务
Redis缓存
MySQL持久化

数据存储格式

redis

# 存储用户点赞状态(SET)
SADD picture_likes:{picture_id} {user_id}  # 用户点赞图片
SREM picture_likes:{picture_id} {user_id}  # 取消点赞# 存储点赞计数器(String)
INCR picture_like_count:{picture_id}       # 点赞数+1
DECR picture_like_count:{picture_id}       # 点赞数-1# 存储用户点赞历史(ZSET)用于做增量同步
ZADD user_likes:{picture_id} {timestamp} {user_id}  # 按时间排序

mysql

下面是用户点赞关系表, 至于 likesCount 则作为字段添加进 picture 表

create table user_likes
(id           bigint auto_incrementprimary key,user_id      bigint                              not null,picture_id   bigint                              not null,created_time timestamp default CURRENT_TIMESTAMP not null,constraint uk_user_pictureunique (user_id, picture_id)
);

核心代码实现

点赞或取消点赞

相关参数构建

根据自己实际情况来

Long userId = userService.getLoginUser().getId();
String key = PICTURE_LIKE_PREFIX + request.getPictureId();
String userIdStr = userId.toString();
String likeCountKey = PICTURE_LIKE_COUNT_PREFIX + request.getPictureId();
String likeTimeKey = PICTURE_LIKE_TIME_PREFIX + request.getPictureId();// 查询用户是否已经点赞
boolean isLiked = Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(key, userId.toString())
);
操作 redis

为了防止指令穿插导致不一致性, 需要保证操作的原子性, 这里使用 管道 + MULTI 和 EXEC 命令来保证原子性和隔离性(也可以使用 lua 脚本来完成)

stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {connection.multi(); // 开启事务if (!isLiked) {// 记录用户点赞关系connection.sAdd(key.getBytes(), userIdStr.getBytes());// 记录用户点赞时间connection.zAdd(likeTimeKey.getBytes(), System.currentTimeMillis() / 1000.0, userIdStr.getBytes());// 增加点赞计数connection.incr(likeCountKey.getBytes());} else {// 移除用户点赞关系connection.sRem(key.getBytes(), userIdStr.getBytes());// 用处用户赞时间connection.zRem(likeTimeKey.getBytes(), userIdStr.getBytes());// 减少点赞计数connection.decr(likeCountKey.getBytes());}return connection.exec();
});

补充: redis 的事务机制

当使用事务来执行多个指令时,通过 MULTI 命令开启事务,将多个指令放入一个事务中,然后使用 EXEC 命令来原子性地执行这些指令。在 EXEC 执行期间,Redis 会按照顺序依次执行事务中的指令,不会被其他客户端的命令打断,从而保证了事务内指令执行的原子性和顺序性,也就确保了两条指令执行的间隔内没有其他指令被执行。

查询点赞数据

这里需要查询出用户是否给图片点赞, 以及图片对应的点赞总数

public List<LikeInfoVO> batchCheckLikeStatus(Long userId, List<Long> pictureIds) {// 1. 使用Pipeline同时查询两种数据List<Object> results = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {// 查询用户点赞状态for (Long picId : pictureIds) {connection.sIsMember((PICTURE_LIKE_PREFIX + picId).getBytes(),userId.toString().getBytes());}// 查询点赞总数// 未匹配的项会返回空for (Long picId : pictureIds) {connection.get((PICTURE_LIKE_COUNT_PREFIX + picId).getBytes());}return null;});// 2. 处理混合结果List<LikeInfoVO> resultMap = new ArrayList<>();int halfSize = results.size() / 2;for (int i = 0; i < halfSize; i++) {Boolean isLiked = (Boolean) results.get(i);Integer likeCount = results.get(i + halfSize) != null ?Integer.parseInt((String) results.get(i + halfSize)) : 0;resultMap.add(new LikeInfoVO(isLiked, likeCount));}return resultMap;
}

将点赞数据封装进响应结果

List<LikeInfoVO> likeStatus = batchCheckLikeStatus(userId, pictureIds);List<PictureVO> vos = IntStream.range(0, records.size()).mapToObj(i -> {PictureVO pictureVO = new PictureVO();BeanUtils.copyProperties(records.get(i), pictureVO);pictureVO.setLike(likeStatus.get(i).getIsLike());pictureVO.setLikesCount(likeStatus.get(i).getLikesCount());return pictureVO;
}).collect(Collectors.toList());

数据同步

增量同步 or 全量同步

使用定时任务来完成将 redis 中数据同步到 mysql, 这里就不使用全量同步了, 一方面全量同步性能底, 再未处理 redis 删除的点赞关系

代码

@Scheduled(fixedRate = 300000)
public void syncIncrementally() {log.info("开始: 增量同步图片用户点赞关系到数据库, 并处理Redis已删除的点赞关系");// 1. 获取Redis最后同步时间戳long lastSyncTime = getLastSyncTimestamp();// 2. 同步新增点赞syncNewLikes(lastSyncTime);// 3. 同步取消点赞syncUnlikes();// 5. 同步图片点赞数量syncPicLikesCount();// 4. 更新同步时间updateSyncTimestamp();log.info("结束: 增量同步图片用户点赞关系到数据库, 并处理Redis已删除的点赞关系");
}
设置同步时间和获取最后同步时间
// 获取最后同步时间(默认返回24小时前的时间戳)
private long getLastSyncTimestamp() {String timestampStr = stringRedisTemplate.opsForValue().get(LAST_SYNC_KEY);return timestampStr != null ?Long.parseLong(timestampStr) :System.currentTimeMillis() - 86400_000; // 默认24小时前
}// 更新同步时间戳为当前时间
private void updateSyncTimestamp() {stringRedisTemplate.opsForValue().set(LAST_SYNC_KEY,String.valueOf(System.currentTimeMillis()));
}
同步新增点赞
private void syncNewLikes(long sinceTime) {// 使用ZSET记录点赞时间戳Set<String> newLikeKeys = stringRedisTemplate.keys(PICTURE_LIKE_PREFIX + "*");Objects.requireNonNull(newLikeKeys).forEach(key -> {long pictureId = Long.parseLong(StrUtil.removePrefix(key, PICTURE_LIKE_PREFIX));// 获取新增点赞用户(ZRANGEBYSCORE)Set<String> newUserIds = stringRedisTemplate.opsForZSet().rangeByScore(PICTURE_LIKE_TIME_PREFIX + pictureId, sinceTime, Double.MAX_VALUE);List<UserLikes> entityList = Objects.requireNonNull(newUserIds).stream().map(userId -> {UserLikes userLikes = new UserLikes();userLikes.setPictureId(pictureId);userLikes.setUserId(Long.parseLong(userId));return userLikes;}).collect(Collectors.toList());// 批量插入并忽略重复的元素if (CollUtil.isNotEmpty(entityList)) {userLikesMapper.insertIgnoreBatch(entityList);}});
}
同步取消点赞
private void syncUnlikes() {Set<String> likeKeys = stringRedisTemplate.keys(PICTURE_LIKE_PREFIX + "*");Objects.requireNonNull(likeKeys).forEach(key -> {Long pictureId = Long.parseLong(key.substring(PICTURE_LIKE_PREFIX.length()));Set<String> members = stringRedisTemplate.opsForSet().members(key);Set<Long> redisUserIds = Objects.requireNonNull(members).stream().map(Long::parseLong).collect(Collectors.toSet());QueryWrapper<UserLikes> wrapper = new QueryWrapper<>();wrapper.select("user_id").eq("picture_id", pictureId);Set<Long> mysqlUserIds = userLikesMapper.selectList(wrapper).stream().map(UserLikes::getUserId).collect(Collectors.toSet());// 找出MySQL有但Redis没有的记录mysqlUserIds.removeAll(redisUserIds);if (CollUtil.isNotEmpty(mysqlUserIds)) {UpdateWrapper<UserLikes> userLikesUpdateWrapper = new UpdateWrapper<>();userLikesUpdateWrapper.eq("picture_id", pictureId).in("user_id", mysqlUserIds);userLikesMapper.delete(userLikesUpdateWrapper);}});
}

文章转载自:

http://nFMQPBIa.qjtbt.cn
http://noJLz58U.qjtbt.cn
http://vVZiBHJG.qjtbt.cn
http://3j6UAFos.qjtbt.cn
http://2Sj9mBCf.qjtbt.cn
http://VfgQAOFp.qjtbt.cn
http://jghncAU1.qjtbt.cn
http://cLhENT6n.qjtbt.cn
http://gWH6BviV.qjtbt.cn
http://b3rtscyP.qjtbt.cn
http://zjaU0Thr.qjtbt.cn
http://4jdqK2hD.qjtbt.cn
http://WCtzro3H.qjtbt.cn
http://oVoJ6lf7.qjtbt.cn
http://jHNinZYP.qjtbt.cn
http://NJc9Vezu.qjtbt.cn
http://le7cCFjP.qjtbt.cn
http://3euy6XRF.qjtbt.cn
http://MYjRDAPI.qjtbt.cn
http://jvaXJU9N.qjtbt.cn
http://ArY2u472.qjtbt.cn
http://8yR1n9l1.qjtbt.cn
http://jJ5T0mco.qjtbt.cn
http://yGlPawPB.qjtbt.cn
http://iYKMZuNW.qjtbt.cn
http://dNXtEyax.qjtbt.cn
http://fk8rGpbD.qjtbt.cn
http://uV6mYSeu.qjtbt.cn
http://xCkQGEBx.qjtbt.cn
http://tNixHMnN.qjtbt.cn
http://www.dtcms.com/wzjs/743673.html

相关文章:

  • 网站logo大全数字图书馆网站建设
  • 北京网络行业协会怎么样优化关键词排名
  • 网站升级建设网站信息报送制度建设
  • 姜堰哪里有网站建设的软件ui设计培训学校
  • 济南制作网站企业wordpress 过滤词
  • 建设网站cms沙井做网站的公司
  • wordpress个人网站后台登陆wordpress自带企业主题下载
  • 成都做网站设计公司价格智能建站系统怎么更换网站模板
  • asp怎么做网站站长必备网站
  • 射阳做网站岳阳市 网站建设
  • j建网站wordpress 回复邮件
  • 魏县专业做网站wordpress控制api使用次数
  • 泉州市第一建设有限公司网站江宁区建设工程质量监督站网站
  • 搜索引擎排名公司网站关键词优化网站设计 方案
  • 上海网站开发团队大型局域网组建方案
  • 最低成本做企业网站 白之家企业免费网站优化服务
  • 做网站有什么比较好看的动效单位网站开发费用是否计入无形资产
  • 昆明建设公司网站网站申请建设
  • 沈阳网站关键词优化做的好吗合肥网站排名
  • 油画网站模板安徽平台网站建设费用
  • 手机浏览器网站开发网站建设单位是什么意思
  • 建设旅游网站的市场分析品牌广告投放
  • 中国建设银行网站分析广州微网站建设效果
  • 微网站制作速成法中国企业500强净利润排名
  • dede企业网站模板wordpress 搜狐视频
  • 网站模板 婴儿wordpress 文章页面模板下载
  • 做网站的图片素材网站有哪些网站 做百度推广有没有效果怎么样
  • 求做外宣图网站网店运营计划书
  • dede一键更新网站wordpress先页面再首页
  • 片头网站网页页面设计叫什么