Redis實戰(3)-數據結構List實戰一之商品信息的有序存儲

概述:本系列博文所涉及的相關內容來源於debug親自錄製的實戰課程:緩存中間件Redis技術入門與應用場景實戰(SpringBoot2.x + 搶紅包系統設計與實戰),感興趣的小夥伴可以點擊自行前往學習(畢竟以視頻的形式來掌握技術 會更快!) ,文章所屬專欄:緩存中間件Redis技術入門與實戰


摘要:電商平臺的管理後端一般有兩大角色的用戶可以使用,一個是系統管理員,一個是平臺的賣家/商家,對於商家而言,管理自個兒的商品是日常工作中再爲普通不過的事情了,本文我們將以“有序存儲並展示電商平臺中商家上傳的各式各樣的商品列表”,這裏的關鍵詞是“有序存儲與展示”,我們將藉助緩存中間件Redis的數據結構~列表List進行實戰實現!


內容:對於Redis的數據結構~列表List,在實際的項目開發實戰中,也算是其中一種比較常見、應用也比較廣泛的數據結構吧!其底層數據存儲結構跟JavaSE集合體系的List有極其相似之處,即數據在底層是有序、排好順序的,在將列表的數據獲取出來的時候,會發現其中的數據確實是已經排好順序的了,給大家繪製了一個簡單的List的存儲和獲取流程圖,如下所示:

從該圖中,可以看出,當我們往Redis的列表List中添加數據時,具有“先進先出”的特性,即所謂的“FIFO”(有點隊列Queue的特性!),而且數據是緊湊、一個挨着一個存儲的!即當我們在往緩存Redis的列表List添加數據時,可以採用“LPush 即從左邊的方向添加”的方式往緩存Redis的List中添加,然後再採用“LPop 即從左邊的方向彈出數據”或者“RPop 即從右邊的方向彈出數據”的方式獲取這一有序存儲的列表數據!


知道了列表List的數據存儲和讀取流程,其實我們也就幾乎知曉了在實際的項目實戰開發中的代碼實現了。下面我們以“電商平臺~商家添加/下架商品時如何將其商品列表有序存儲至緩存Redis的List中,每次獲取商家當前的商品列表時可以直接從緩存中讀取,減少每個商家在每次登陸之後都需要走數據庫DB頻繁查詢 所帶來的壓力!

(1)首先,當然是需要來個“產品信息表”啦,其完整的DDL(即數據定義語言)如下所示:

CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '商品名稱',
  `user_id` int(11) NOT NULL COMMENT '所屬商戶id',
  `scan_total` int(255) DEFAULT NULL COMMENT '瀏覽量',
  `is_active` tinyint(255) DEFAULT '1' COMMENT '是否有效',  PRIMARY KEY (`id`),
  KEY `indx_scan_total` (`scan_total`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商戶商品表';

(2)然後,當然是需要開發一個Controller啦,在該Controller中我們需要開設兩個請求方法,一個是給商戶使用的“添加商品”(進DB,並塞入Redis),另外一個是獲取當前商戶已添加的“商品列表”,其完整的源代碼如下所示:  

/**
 * 列表List實戰-商戶商品列表存儲
 * @Author:debug (SteadyJack)
 * @Link: weixin-> debug0868 qq-> 1948831260
 * @Date: 2019/10/30 20:58
 **/
@RestController
@RequestMapping("list")
public class ListController extends AbstractController{
    @Autowired
    private ListService listService;
    //添加
    @RequestMapping(value = "put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public BaseResponse put(@RequestBody Product product,BindingResult result){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            log.info("--商戶商品信息:{}",product);
            response.setData(listService.addProduct(product));
        }catch (Exception e){
            log.error("--List實戰-商戶商品-添加-發生異常:",e.fillInStackTrace());
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }
    //獲取列表詳情
    @RequestMapping(value = "get",method = RequestMethod.GET)
    public BaseResponse get(@RequestParam("userId") final Integer userId){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(listService.getHistoryProducts(userId));
        }catch (Exception e){
            log.error("--List實戰-商戶商品-獲取列表-發生異常:",e.fillInStackTrace());
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }
}

(3)緊接着,我們需要開發Controller對應的Service,其職責當然是用來處理真正的業務邏輯,“添加商品”時,它負責將該商品信息添加進DB數據庫,並添加進緩存Redis中;“獲取商品”時,自然而然是從緩存Redis獲取出List列表數據,其完整的源代碼如下所示:  

/**
 * 列表List服務
 * @Author:debug (SteadyJack)
 * @Link: weixin-> debug0868 qq-> 1948831260
 * @Date: 2019/10/30 9:48
 **/
@Service
public class ListService {
    public static final Logger log= LoggerFactory.getLogger(ListService.class);
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    //添加商品
    @Transactional(rollbackFor = Exception.class)
    public Integer addProduct(Product product) throws Exception{
        if (product!=null){
            product.setId(null);
                //將該商品塞入數據庫DB中
            productMapper.insertSelective(product);
            Integer id=product.getId();
            if (id>0){
                       //將該商品塞入緩存Redis中
                this.pushRedisService(product);
            }
            return id;
        }
        return -1;
    }
    //TODO:往緩存中塞信息-可以抽取到ListRedisService
    private void pushRedisService(final Product product) throws Exception{
        ListOperations<String,Product> listOperations=redisTemplate.opsForList();
        listOperations.leftPush(Constant.RedisListPrefix+product.getUserId(),product);
    }
    //獲取歷史發佈的商品列表
    public List<Product> getHistoryProducts(final Integer userId) throws Exception{
        List<Product> list= Lists.newLinkedList();
        ListOperations<String,Product> listOperations=redisTemplate.opsForList();
        final String key=Constant.RedisListPrefix+userId;
        //TODO:倒序->userID=10010 ->Rabbitmq入門與實戰,Redis入門與實戰,SpringBoot項目實戰
        list=listOperations.range(key,0,listOperations.size(key));
        log.info("--倒序:{}",list);
        //TODO:順序->userID=10010 ->SpringBoot項目實戰,Redis入門與實戰,Rabbitmq入門與實戰
        //Collections.reverse(list);
        //log.info("--順序:{}",list);
        //TODO:彈出來移除的方式
        //Product entity=listOperations.rightPop(key);
        //while (entity!=null){
            //list.add(entity);
            //entity=listOperations.rightPop(key);
        //}
        return list;
    }
}

(4)至此,我們的代碼實戰就完畢了,最後我們就基於Postman進入測試環節吧,我們給商戶10010添加兩個商品吧,如下所示:

完成之後還可以前往數據庫Mysql中查看剛剛已經添加完成的商品列表,如下圖所示:

最後,我們再在Postman發起“獲取當前商戶已經添加完成的商品列表-有序展示”(可以通過修改代碼的方式,實現“順序”、“倒序”等功效),如下所示:

好了,本篇文章我們就介紹到這裏了,建議各位小夥伴一定要照着文章提供的樣例代碼擼一擼,只有擼過才能知道這玩意是咋用的,否則就成了“空談者”!對Redis相關技術棧以及實際應用場景實戰感興趣的小夥伴可以咱們51cto學院 debug親自錄製的課程進行學習:緩存中間件Redis技術入門與應用場景實戰(SpringBoot2.x + 搶紅包系統設計與實戰)


補充:

1、本文涉及到的相關的源代碼可以到此地址,check出來進行查看學習:https://gitee.com/steadyjack/SpringBootRedis

2、目前debug已將本文所涉及的內容整理錄製成視頻教程,感興趣的小夥伴可以前往觀看學習:https://edu.51cto.com/course/20384.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章