<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis如何高效實現(xiàn)點贊、取消點贊功能

          共 37643字,需瀏覽 76分鐘

           ·

          2021-11-09 12:32

          ????關注后回復 “進群” ,拉你進程序員交流群????


          來源丨blog.csdn.net/lsy0903/article/details/103949459


          基于 SpringCloud, 用戶發(fā)起點贊、取消點贊后先存入 Redis 中,再每隔兩小時從 Redis 讀取點贊數(shù)據(jù)寫入數(shù)據(jù)庫中做持久化存儲。

          點贊功能在很多系統(tǒng)中都有,但別看功能小,想要做好需要考慮的東西還挺多的。

          點贊、取消點贊是高頻次的操作,若每次都讀寫數(shù)據(jù)庫,大量的操作會影響數(shù)據(jù)庫性能,所以需要做緩存。

          至于多久從 Redis 取一次數(shù)據(jù)存到數(shù)據(jù)庫中,根據(jù)項目的實際情況定吧,我是暫時設了兩個小時。

          項目需求需要查看都誰點贊了,所以要存儲每個點贊的點贊人、被點贊人,不能簡單的做計數(shù)。

          文章分四部分介紹:

          • Redis 緩存設計及實現(xiàn)

          • 數(shù)據(jù)庫設計

          • 數(shù)據(jù)庫操作

          • 開啟定時任務持久化存儲到數(shù)據(jù)庫

          一、Redis 緩存設計及實現(xiàn)

          1.1 Redis 安裝及運行

          Redis 安裝請自行查閱相關教程。

          說下Docker 安裝運行 Redis

          docker run -d -p 6379:6379 redis:4.0.8  

          如果已經(jīng)安裝了 Redis,打開命令行,輸入啟動 Redis 的命令

          redis-server  

          1.2 Redis 與 SpringBoot 項目的整合

          1.在 pom.xml 中引入依賴

          <dependency>  
              <groupId>org.springframework.boot</groupId>  
              <artifactId>spring-boot-starter-data-redis</artifactId>  
          </dependency>  

          2.在啟動類上添加注釋 @EnableCaching

          @SpringBootApplication  
          @EnableDiscoveryClient  
          @EnableSwagger2  
          @EnableFeignClients(basePackages = "com.solo.coderiver.project.client")  
          @EnableCaching  
          public class UserApplication {  
            
              public static void main(String[] args) {  
                  SpringApplication.run(UserApplication.classargs);  
              }  
          }  

          3.編寫 Redis 配置類 RedisConfig

          import com.fasterxml.jackson.annotation.JsonAutoDetect;  
          import com.fasterxml.jackson.annotation.PropertyAccessor;  
          import com.fasterxml.jackson.databind.ObjectMapper;  
          import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
          import org.springframework.context.annotation.Bean;  
          import org.springframework.context.annotation.Configuration;  
          import org.springframework.data.redis.connection.RedisConnectionFactory;  
          import org.springframework.data.redis.core.RedisTemplate;  
          import org.springframework.data.redis.core.StringRedisTemplate;  
          import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;  
            
          import java.net.UnknownHostException;  
            
            
          @Configuration  
          public class RedisConfig {  
            
              @Bean  
              @ConditionalOnMissingBean(name = "redisTemplate")  
              public RedisTemplate<String, Object> redisTemplate(  
                      RedisConnectionFactory redisConnectionFactory)
            
                      throws UnknownHostException 
          {  
            
                  Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);  
                  ObjectMapper om = new ObjectMapper();  
                  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);  
                  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  
                  jackson2JsonRedisSerializer.setObjectMapper(om);  
            
                  RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();  
                  template.setConnectionFactory(redisConnectionFactory);  
                  template.setKeySerializer(jackson2JsonRedisSerializer);  
                  template.setValueSerializer(jackson2JsonRedisSerializer);  
                  template.setHashKeySerializer(jackson2JsonRedisSerializer);  
                  template.setHashValueSerializer(jackson2JsonRedisSerializer);  
                  template.afterPropertiesSet();  
                  return template;  
              }  
            
            
              @Bean  
              @ConditionalOnMissingBean(StringRedisTemplate.class)  
              public StringRedisTemplate stringRedisTemplate(  
                      RedisConnectionFactory redisConnectionFactory)  
                      throws UnknownHostException 
          {  
                  StringRedisTemplate template = new StringRedisTemplate();  
                  template.setConnectionFactory(redisConnectionFactory);  
                  return template;  
              }  
          }  

          至此 Redis 在 SpringBoot 項目中的配置已經(jīng)完成,可以愉快的使用了。

          1.3 Redis 的數(shù)據(jù)結(jié)構(gòu)類型

          Redis 可以存儲鍵與5種不同數(shù)據(jù)結(jié)構(gòu)類型之間的映射,這5種數(shù)據(jù)結(jié)構(gòu)類型分別為String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。

          下面來對這5種數(shù)據(jù)結(jié)構(gòu)類型作簡單的介紹:

          圖片

          1.4 點贊數(shù)據(jù)在 Redis 中的存儲格式

          用 Redis 存儲兩種數(shù)據(jù),一種是記錄點贊人、被點贊人、點贊狀態(tài)的數(shù)據(jù),另一種是每個用戶被點贊了多少次,做個簡單的計數(shù)。

          由于需要記錄點贊人和被點贊人,還有點贊狀態(tài)(點贊、取消點贊),還要固定時間間隔取出 Redis 中所有點贊數(shù)據(jù),分析了下 Redis 數(shù)據(jù)格式中 Hash 最合適。

          因為 Hash 里的數(shù)據(jù)都是存在一個鍵里,可以通過這個鍵很方便的把所有的點贊數(shù)據(jù)都取出。這個鍵里面的數(shù)據(jù)還可以存成鍵值對的形式,方便存入點贊人、被點贊人和點贊狀態(tài)。

          設點贊人的 id 為 likedPostId,被點贊人的 id 為 likedUserId ,點贊時狀態(tài)為 1,取消點贊狀態(tài)為 0。將點贊人 id 和被點贊人 id 作為鍵,兩個 id 中間用 :: 隔開,點贊狀態(tài)作為值。

          所以如果用戶點贊,存儲的鍵為:likedUserId::likedPostId,對應的值為 1 。取消點贊,存儲的鍵為:likedUserId::likedPostId,對應的值為 0 。取數(shù)據(jù)時把鍵用 :: 切開就得到了兩個id,也很方便。

          在可視化工具 RDM 中看到的是這樣子

          圖片
          圖片

          1.5 操作 Redis

          將具體操作方法封裝到了 RedisService 接口里

          RedisService.java

          import com.solo.coderiver.user.dataobject.UserLike;  
          import com.solo.coderiver.user.dto.LikedCountDTO;  
            
          import java.util.List;  
            
          public interface RedisService {  
            
              /**  
               * 點贊。狀態(tài)為1  
               * @param likedUserId  
               * @param likedPostId  
               */
            
              void saveLiked2Redis(String likedUserId, String likedPostId);  
            
              /**  
               * 取消點贊。將狀態(tài)改變?yōu)?  
               * @param likedUserId  
               * @param likedPostId  
               */
            
              void unlikeFromRedis(String likedUserId, String likedPostId);  
            
              /**  
               * 從Redis中刪除一條點贊數(shù)據(jù)  
               * @param likedUserId  
               * @param likedPostId  
               */
            
              void deleteLikedFromRedis(String likedUserId, String likedPostId);  
            
              /**  
               * 該用戶的點贊數(shù)加1  
               * @param likedUserId  
               */
            
              void incrementLikedCount(String likedUserId);  
            
              /**  
               * 該用戶的點贊數(shù)減1  
               * @param likedUserId  
               */
            
              void decrementLikedCount(String likedUserId);  
            
              /**  
               * 獲取Redis中存儲的所有點贊數(shù)據(jù)  
               * @return  
               */
            
              List<UserLike> getLikedDataFromRedis();  
            
              /**  
               * 獲取Redis中存儲的所有點贊數(shù)量  
               * @return  
               */
            
              List<LikedCountDTO> getLikedCountFromRedis();  
            
          }  

          實現(xiàn)類 RedisServiceImpl.java

          import com.solo.coderiver.user.dataobject.UserLike;  
          import com.solo.coderiver.user.dto.LikedCountDTO;  
          import com.solo.coderiver.user.enums.LikedStatusEnum;  
          import com.solo.coderiver.user.service.LikedService;  
          import com.solo.coderiver.user.service.RedisService;  
          import com.solo.coderiver.user.utils.RedisKeyUtils;  
          import lombok.extern.slf4j.Slf4j;  
          import org.springframework.beans.factory.annotation.Autowired;  
          import org.springframework.data.redis.core.Cursor;  
          import org.springframework.data.redis.core.RedisTemplate;  
          import org.springframework.data.redis.core.ScanOptions;  
          import org.springframework.stereotype.Service;  
            
          import java.util.ArrayList;  
          import java.util.List;  
          import java.util.Map;  
            
          @Service  
          @Slf4j  
          public class RedisServiceImpl implements RedisService {  
            
              @Autowired  
              RedisTemplate redisTemplate;  
            
              @Autowired  
              LikedService likedService;  
            
              @Override  
              public void saveLiked2Redis(String likedUserId, String likedPostId) {  
                  String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);  
                  redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.LIKE.getCode());  
              }  
            
              @Override  
              public void unlikeFromRedis(String likedUserId, String likedPostId) {  
                  String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);  
                  redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.UNLIKE.getCode());  
              }  
            
              @Override  
              public void deleteLikedFromRedis(String likedUserId, String likedPostId) {  
                  String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);  
                  redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);  
              }  
            
              @Override  
              public void incrementLikedCount(String likedUserId) {  
                  redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, 1);  
              }  
            
              @Override  
              public void decrementLikedCount(String likedUserId) {  
                  redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1);  
              }  
            
              @Override  
              public List<UserLike> getLikedDataFromRedis() {  
                  Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);  
                  List<UserLike> list = new ArrayList<>();  
                  while (cursor.hasNext()){  
                      Map.Entry<Object, Object> entry = cursor.next();  
                      String key = (String) entry.getKey();  
                      //分離出 likedUserId,likedPostId  
                      String[] split = key.split("::");  
                      String likedUserId = split[0];  
                      String likedPostId = split[1];  
                      Integer value = (Integer) entry.getValue();  
            
                      //組裝成 UserLike 對象  
                      UserLike userLike = new UserLike(likedUserId, likedPostId, value);  
                      list.add(userLike);  
            
                      //存到 list 后從 Redis 中刪除  
                      redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);  
                  }  
            
                  return list;  
              }  
            
              @Override  
              public List<LikedCountDTO> getLikedCountFromRedis() {  
                  Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);  
                  List<LikedCountDTO> list = new ArrayList<>();  
                  while (cursor.hasNext()){  
                      Map.Entry<Object, Object> map = cursor.next();  
                      //將點贊數(shù)量存儲在 LikedCountDT  
                      String key = (String)map.getKey();  
                      LikedCountDTO dto = new LikedCountDTO(key, (Integer) map.getValue());  
                      list.add(dto);  
                      //從Redis中刪除這條記錄  
                      redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);  
                  }  
                  return list;  
              }  
          }  

          用到的工具類和枚舉類

          RedisKeyUtils, 用于根據(jù)一定規(guī)則生成 key

          public class RedisKeyUtils {  
            
              //保存用戶點贊數(shù)據(jù)的key  
              public static final String MAP_KEY_USER_LIKED = "MAP_USER_LIKED";  
              //保存用戶被點贊數(shù)量的key  
              public static final String MAP_KEY_USER_LIKED_COUNT = "MAP_USER_LIKED_COUNT";  
            
              /**  
               * 拼接被點贊的用戶id和點贊的人的id作為key。格式 222222::333333  
               * @param likedUserId 被點贊的人id  
               * @param likedPostId 點贊的人的id  
               * @return  
               */
            
              public static String getLikedKey(String likedUserId, String likedPostId){  
                  StringBuilder builder = new StringBuilder();  
                  builder.append(likedUserId);  
                  builder.append("::");  
                  builder.append(likedPostId);  
                  return builder.toString();  
              }  
          }  

          LikedStatusEnum 用戶點贊狀態(tài)的枚舉類

          package com.solo.coderiver.user.enums;  
            
          import lombok.Getter;  
            
          /**  
           * 用戶點贊的狀態(tài)  
           */
            
          @Getter  
          public enum LikedStatusEnum {  
              LIKE(1"點贊"),  
              UNLIKE(0"取消點贊/未點贊"),  
              ;  
            
              private Integer code;  
            
              private String msg;  
            
              LikedStatusEnum(Integer code, String msg) {  
                  this.code = code;  
                  this.msg = msg;  
              }  
          }  

          二、數(shù)據(jù)庫設計

          數(shù)據(jù)庫表中至少要包含三個字段:被點贊用戶id,點贊用戶id,點贊狀態(tài)。再加上主鍵id,創(chuàng)建時間,修改時間就行了。學習資料:Java進階視頻資源

          建表語句

          create table `user_like`(  
              `id` int not null auto_increment,  
              `liked_user_id` varchar(32not null comment '被點贊的用戶id',  
              `liked_post_id` varchar(32not null comment '點贊的用戶id',  
              `status` tinyint(1default '1' comment '點贊狀態(tài),0取消,1點贊',  
              `create_time` timestamp not null default current_timestamp comment '創(chuàng)建時間',  
            `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改時間',  
              primary key(`id`),  
              INDEX `liked_user_id`(`liked_user_id`),  
              INDEX `liked_post_id`(`liked_post_id`)  
          comment '用戶點贊表';  

          對應的對象 UserLike

          import com.solo.coderiver.user.enums.LikedStatusEnum;  
          import lombok.Data;  
            
          import javax.persistence.Entity;  
          import javax.persistence.GeneratedValue;  
          import javax.persistence.GenerationType;  
          import javax.persistence.Id;  
            
          /**  
           * 用戶點贊表  
           */
            
          @Entity  
          @Data  
          public class UserLike {  
            
              //主鍵id  
              @Id  
              @GeneratedValue(strategy = GenerationType.IDENTITY)  
              private Integer id;  
            
              //被點贊的用戶的id  
              private String likedUserId;  
            
              //點贊的用戶的id  
              private String likedPostId;  
            
              //點贊的狀態(tài).默認未點贊  
              private Integer status = LikedStatusEnum.UNLIKE.getCode();  
            
              public UserLike() {  
              }  
            
              public UserLike(String likedUserId, String likedPostId, Integer status) {  
                  this.likedUserId = likedUserId;  
                  this.likedPostId = likedPostId;  
                  this.status = status;  
              }  
          }  

          三、數(shù)據(jù)庫操作

          操作數(shù)據(jù)庫同樣封裝在接口中

          LikedService

          import com.solo.coderiver.user.dataobject.UserLike;  
          import org.springframework.data.domain.Page;  
          import org.springframework.data.domain.Pageable;  
            
          import java.util.List;  
            
          public interface LikedService {  
            
              /**  
               * 保存點贊記錄  
               * @param userLike  
               * @return  
               */
            
              UserLike save(UserLike userLike);  
            
              /**  
               * 批量保存或修改  
               * @param list  
               */
            
              List<UserLike> saveAll(List<UserLike> list);  
            
            
              /**  
               * 根據(jù)被點贊人的id查詢點贊列表(即查詢都誰給這個人點贊過)  
               * @param likedUserId 被點贊人的id  
               * @param pageable  
               * @return  
               */
            
              Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable);  
            
              /**  
               * 根據(jù)點贊人的id查詢點贊列表(即查詢這個人都給誰點贊過)  
               * @param likedPostId  
               * @param pageable  
               * @return  
               */
            
              Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable);  
            
              /**  
               * 通過被點贊人和點贊人id查詢是否存在點贊記錄  
               * @param likedUserId  
               * @param likedPostId  
               * @return  
               */
            
              UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId);  
            
              /**  
               * 將Redis里的點贊數(shù)據(jù)存入數(shù)據(jù)庫中  
               */
            
              void transLikedFromRedis2DB();  
            
              /**  
               * 將Redis中的點贊數(shù)量數(shù)據(jù)存入數(shù)據(jù)庫  
               */
            
              void transLikedCountFromRedis2DB();  
            
          }  

          LikedServiceImpl 實現(xiàn)類

          import com.solo.coderiver.user.dataobject.UserInfo;  
          import com.solo.coderiver.user.dataobject.UserLike;  
          import com.solo.coderiver.user.dto.LikedCountDTO;  
          import com.solo.coderiver.user.enums.LikedStatusEnum;  
          import com.solo.coderiver.user.repository.UserLikeRepository;  
          import com.solo.coderiver.user.service.LikedService;  
          import com.solo.coderiver.user.service.RedisService;  
          import com.solo.coderiver.user.service.UserService;  
          import lombok.extern.slf4j.Slf4j;  
          import org.springframework.beans.factory.annotation.Autowired;  
          import org.springframework.data.domain.Page;  
          import org.springframework.data.domain.Pageable;  
          import org.springframework.stereotype.Service;  
          import org.springframework.transaction.annotation.Transactional;  
            
          import java.util.List;  
            
          @Service  
          @Slf4j  
          public class LikedServiceImpl implements LikedService {  
            
              @Autowired  
              UserLikeRepository likeRepository;  
            
              @Autowired  
              RedisService redisService;  
            
              @Autowired  
              UserService userService;  
            
              @Override  
              @Transactional  
              public UserLike save(UserLike userLike) {  
                  return likeRepository.save(userLike);  
              }  
            
              @Override  
              @Transactional  
              public List<UserLike> saveAll(List<UserLike> list) {  
                  return likeRepository.saveAll(list);  
              }  
            
              @Override  
              public Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable) {  
                  return likeRepository.findByLikedUserIdAndStatus(likedUserId, LikedStatusEnum.LIKE.getCode(), pageable);  
              }  
            
              @Override  
              public Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable) {  
                  return likeRepository.findByLikedPostIdAndStatus(likedPostId, LikedStatusEnum.LIKE.getCode(), pageable);  
              }  
            
              @Override  
              public UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId) {  
                  return likeRepository.findByLikedUserIdAndLikedPostId(likedUserId, likedPostId);  
              }  
            
              @Override  
              @Transactional  
              public void transLikedFromRedis2DB() {  
                  List<UserLike> list = redisService.getLikedDataFromRedis();  
                  for (UserLike like : list) {  
                      UserLike ul = getByLikedUserIdAndLikedPostId(like.getLikedUserId(), like.getLikedPostId());  
                      if (ul == null){  
                          //沒有記錄,直接存入  
                          save(like);  
                      }else{  
                          //有記錄,需要更新  
                          ul.setStatus(like.getStatus());  
                          save(ul);  
                      }  
                  }  
              }  
            
              @Override  
              @Transactional  
              public void transLikedCountFromRedis2DB() {  
                  List<LikedCountDTO> list = redisService.getLikedCountFromRedis();  
                  for (LikedCountDTO dto : list) {  
                      UserInfo user = userService.findById(dto.getId());  
                      //點贊數(shù)量屬于無關緊要的操作,出錯無需拋異常  
                      if (user != null){  
                          Integer likeNum = user.getLikeNum() + dto.getCount();  
                          user.setLikeNum(likeNum);  
                          //更新點贊數(shù)量  
                          userService.updateInfo(user);  
                      }  
                  }  
              }  
          }  

          數(shù)據(jù)庫的操作就這些,主要還是增刪改查。學習資料:Java進階視頻資源

          四、開啟定時任務持久化存儲到數(shù)據(jù)庫

          定時任務 Quartz 很強大,就用它了。

          Quartz 使用步驟:

          1.添加依賴

          <dependency>  
              <groupId>org.springframework.boot</groupId>  
              <artifactId>spring-boot-starter-quartz</artifactId>  
          </dependency>  

          2.編寫配置文件

          package com.solo.coderiver.user.config;  
            
          import com.solo.coderiver.user.task.LikeTask;  
          import org.quartz.*;  
          import org.springframework.context.annotation.Bean;  
          import org.springframework.context.annotation.Configuration;  
            
          @Configuration  
          public class QuartzConfig {  
            
              private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";  
            
              @Bean  
              public JobDetail quartzDetail(){  
                  return JobBuilder.newJob(LikeTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();  
              }  
            
              @Bean  
              public Trigger quartzTrigger(){  
                  SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()  
          //                .withIntervalInSeconds(10)  //設置時間周期單位秒  
                          .withIntervalInHours(2)  //兩個小時執(zhí)行一次  
                          .repeatForever();  
                  return TriggerBuilder.newTrigger().forJob(quartzDetail())  
                          .withIdentity(LIKE_TASK_IDENTITY)  
                          .withSchedule(scheduleBuilder)  
                          .build();  
              }  
          }  

          3.編寫執(zhí)行任務的類繼承自 QuartzJobBean

          package com.solo.coderiver.user.task;  
            
          import com.solo.coderiver.user.service.LikedService;  
          import lombok.extern.slf4j.Slf4j;  
          import org.apache.commons.lang.time.DateUtils;  
          import org.quartz.JobExecutionContext;  
          import org.quartz.JobExecutionException;  
          import org.springframework.beans.factory.annotation.Autowired;  
          import org.springframework.scheduling.quartz.QuartzJobBean;  
            
          import java.text.SimpleDateFormat;  
          import java.util.Date;  
            
          /**  
           * 點贊的定時任務  
           */
            
          @Slf4j  
          public class LikeTask extends QuartzJobBean {  
            
              @Autowired  
              LikedService likedService;  
            
              private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
            
              @Override  
              protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {  
            
                  log.info("LikeTask-------- {}", sdf.format(new Date()));  
            
                  //將 Redis 里的點贊信息同步到數(shù)據(jù)庫里  
                  likedService.transLikedFromRedis2DB();  
                  likedService.transLikedCountFromRedis2DB();  
              }  
          }  

          在定時任務中直接調(diào)用 LikedService 封裝的方法完成數(shù)據(jù)同步。

          以上就是點贊功能的設計與實現(xiàn),不足之處還請各位大佬多多指教。

          另外,點贊/取消點贊 跟 點贊數(shù) +1/ -1 應該保證是原子操作,不然出現(xiàn)并發(fā)問題就會有兩條重復的點贊記錄,所以要給整個原子操作加鎖。

          同時需要在Spring Boot 的系統(tǒng)關閉鉤子函數(shù)中補充同步redis中點贊數(shù)據(jù)到mysql中的過程 . 不然有可能出現(xiàn)距離上一次同步1小時59分的時候服務器更新,把整整兩小時的點贊數(shù)據(jù)都給清空了。如果點贊設計到比較重要活動業(yè)務的話這就很尷尬了 。

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點擊??卡片,關注后回復【面試題】即可獲取

          在看點這里好文分享給更多人↓↓

          瀏覽 22
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕无码视频在线观看 | 亚日韩欧美在线视频 | 无码精品黑人 | 国产肉体ⅩXXX137大胆图片 | 8809鲁大师日韩版免费使用 |