最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot整合Redis實現(xiàn)緩存分頁數據查詢功能

 更新時間:2023年06月20日 10:16:19   作者:互聯(lián)網小阿祥  
類似淘寶首頁,這些商品是從數據庫中查出來的嗎,答案肯定不是,本文我們就通過一個案例實操一下,首頁熱點數據怎么放到Redis中去查詢,感興趣的同學可以參考一下

正式觀看本文之前,設想一個問題,高并發(fā)情況下,首頁列表數據怎么做?

類似淘寶首頁,這些商品是從數據庫中查出來的嗎?答案肯定不是,在高并發(fā)的情況下,數據庫是扛不住的,那么我們要怎么去扛住C端端大并發(fā)量呢,這快我們可以借助Redis,我們知道Redis是一個基于內存的NoSQL數據庫。學過操作系統(tǒng)我們都知道,內存要比磁盤的效率大的多,那我們Redis就是基于內存的,而數據庫是基于磁盤的。

我們現(xiàn)在知道要用Redis去做首頁數據的分頁,那么我們應該用Redis的那種數據結構來做呢。

Redis有5種基本的數據結構,我們這里用list類型做分頁。

在 Redis 中,List(列表)類型是按照元素的插入順序排序的字符串列表。你可以在列表的頭部(左邊)或者尾部(右部)添加新的元素。

ok,那么接下來我們就通過一個案例實操一下,首頁熱點數據怎么放到Redis中去查詢。

SpringBoot整合RedisTemplate這里就不做過多介紹啦,大家可以網上找篇博文 整合一下。

<!-- 創(chuàng)建SpringBoot項目加入redis的starter依賴 -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

編寫ProductService,定于數據分頁方法。

public interface ProductService {
    Map<String,Object> productListPage(int current, int size) throws InterruptedException;
}

編寫ProductServiceImpl實現(xiàn)類。

/**
 * @author lixiang
 * @date 2023/6/18 21:01
 */
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
    private static final String PRODUCT_LIST_KEY = "product:list";
    private static final List<Product> PRODUCT_LIST;
    //模擬從數據庫中查出來的數據
    static {
        PRODUCT_LIST = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            Product product = new Product();
            product.setId(UUID.randomUUID().toString().replace("-", ""));
            product.setName("商品名稱:" + i);
            product.setDesc("商品描述:" + i);
            product.setPrice(new BigDecimal(i));
            product.setInventory(2);
            PRODUCT_LIST.add(product);
        }
    }
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Map<String, Object> productListPage(int current, int size) throws InterruptedException {
        //從緩存中拿到分頁數據
        List<Product> productList = getProductListByRedis(current, size);
        if (productList == null || productList.size() == 0) {
            log.info("當前緩存中無分頁數據,當前頁:" + current + ",頁大小:" + size);
            //從數據庫中拿到分頁數據
            productList = getProductListByDataSource(current, size);
        }
        Map<String, Object> resultMap = new HashMap<>();
        //計算當前總頁數
        int totalPage = (PRODUCT_LIST.size() + size - 1) / size;
        resultMap.put("total", PRODUCT_LIST.size());
        resultMap.put("data", productList);
        resultMap.put("pages", totalPage);
        return resultMap;
    }
    private List<Product> getProductListByRedis(int current, int size) {
        log.info("從Redis取出商品信息列表,當前頁:" + current + ",頁大小:" + size);
        // 計算總頁數
        int pages = pages(size);
        // 起始位置
        int start = current <= 0 ? 0 : (current > pages ? (pages - 1) * size : (current - 1) * size);
        // 終止位置
        int end = start+size-1;
        List<Product> list = redisTemplate.opsForList().range(PRODUCT_LIST_KEY, start, end);
        List<Product> productList = list;
        return productList;
    }
    /**
     * 獲取商品信息集合
     *
     * @return
     */
    private List<Product> getProductListByDataSource(int current, int size) throws InterruptedException {
        //模擬從DB查詢需要300ms
        Thread.sleep(300);
        log.info("從數據庫取出商品信息列表,當前頁:" + current + ",頁大小:" + size);
        // 計算總頁數
        int pages = pages(size);
        // 起始位置
        int start = current <= 0 ? 0 : (current > pages ? (pages - 1) * size : (current - 1) * size);
        //數據緩存到redis中
        redisTemplate.opsForList().rightPushAll(PRODUCT_LIST_KEY, PRODUCT_LIST);
        //設置當前key過期時間為1個小時
        redisTemplate.expire(PRODUCT_LIST_KEY,1000*60*60, TimeUnit.MILLISECONDS);
        return PRODUCT_LIST.stream().skip(start).limit(size).collect(Collectors.toList());
    }
    /**
     *  獲取總頁數
     * @param size
     * @return
     */
    private Integer pages(int size){
        int pages = PRODUCT_LIST.size() % size == 0 ? PRODUCT_LIST.size() / size : PRODUCT_LIST.size() / size + 1;
        return pages;
    }
}

ok,然后編寫controller,進行測試。

@RestController
@RequestMapping("/api/v1/product")
public class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/page")
    public Map<String,Object> page(@RequestParam("current") int current,@RequestParam("size") int size){
        Map<String, Object> stringObjectMap;
        try {
            stringObjectMap = productService.productListPage(current, size);
        } catch (InterruptedException e) {
            stringObjectMap = new HashMap<>();
        }
        return stringObjectMap;
    }
}

當第一次訪問的時候,先去Redis中查詢,發(fā)現(xiàn)沒有,然后就去查DB,將要緩存的數據頁放到Redis中。

第二次訪問的時候。就直接訪問Redis啦

通過Redis和DB查詢的對比,我們發(fā)現(xiàn)從Redis中拿出來只用了18ms,從公DB中需要300ms,由此可見Redis的一個強大之處。

那么我們觀察一下查詢邏輯,會不會有什么問題。

    public Map<String, Object> productListPage(int current, int size) throws InterruptedException {
        //從緩存中拿到分頁數據
        List<Product> productList = getProductListByRedis(current, size);
        if (productList == null || productList.size() == 0) {
            log.info("當前緩存中無分頁數據,當前頁:" + current + ",頁大小:" + size);
            //從數據庫中拿到分頁數據
            productList = getProductListByDataSource(current, size);
        }
    }

設想,假如某一時刻,Redis中的緩存失效啦,大量的請求,全部查到DB上,也會帶來一個災難。所以這快又涉及到一個緩存擊穿的問題。

解決緩存擊穿

  • 方案一:永不過期
    • 提前把熱點數據不設置過期時間,后臺異步更新緩存。
  • 方案二:加互斥鎖或隊列
    • 其實我理解緩存擊穿和緩存穿透差不多,所以加一個互斥鎖,讓一個線程正常請求數據庫,其他線程等待即可(這里可以使用線程池來處理),都創(chuàng)建完緩存,讓其他線程請求緩存即可。

到此這篇關于SpringBoot整合Redis實現(xiàn)緩存分頁數據查詢功能的文章就介紹到這了,更多相關SpringBoot Redis數據查詢內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring Boot中WebSocket常用使用方法詳解

    Spring Boot中WebSocket常用使用方法詳解

    本文從WebSocket的基礎概念出發(fā),詳細介紹了Spring Boot集成WebSocket的步驟,并重點講解了常用的使用方法,包括簡單消息收發(fā)、點對點消息發(fā)送、消息攔截與認證,以及不使用接口而是基于注解的WebSocket實現(xiàn)方式,感興趣的朋友一起看看吧
    2025-07-07
  • Mybatis Interceptor 攔截器的實現(xiàn)

    Mybatis Interceptor 攔截器的實現(xiàn)

    這篇文章主要介紹了Mybatis Interceptor 攔截器的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Java 前臺加后臺精品圖書管理系統(tǒng)的實現(xiàn)

    Java 前臺加后臺精品圖書管理系統(tǒng)的實現(xiàn)

    相信每一個學生學編程的時候,應該都會寫一個小項目——圖書管理系統(tǒng)。為什么這么說呢?我認為一個學校的氛圍很大一部分可以從圖書館的氛圍看出來,而圖書管理系統(tǒng)這個不大不小的項目,接觸的多,也比較熟悉,不會有陌生感,能夠練手,又有些難度,所以我的小項目也來了
    2021-11-11
  • 六個Java集合使用時需要注意的事項

    六個Java集合使用時需要注意的事項

    這篇文章主要為大家詳細介紹了六個Java集合使用時需要注意的事項,文中的示例代碼講解詳細,對我們學習java有一定的幫助,需要的可以參考一下
    2023-01-01
  • spring-boot-maven-plugin:打包時排除provided依賴問題

    spring-boot-maven-plugin:打包時排除provided依賴問題

    這篇文章主要介紹了spring-boot-maven-plugin:打包時排除provided依賴問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 使用Java實現(xiàn)將一個正整數分解質因數

    使用Java實現(xiàn)將一個正整數分解質因數

    這篇文章主要介紹了如何使用Java語言實現(xiàn)將一個正整數分解為質因數的功能,首先,我們定義了一個正整數并調用一個方法來輸出其質因數分解結果,需要的朋友可以參考下
    2026-01-01
  • Spring實戰(zhàn)之緩存使用condition操作示例

    Spring實戰(zhàn)之緩存使用condition操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之緩存使用condition操作,結合實例形式分析了Spring緩存使用condition具體配置、屬性、領域模型等相關操作技巧與注意事項,需要的朋友可以參考下
    2020-01-01
  • 完美解決因數據庫一次查詢數據量過大導致的內存溢出問題

    完美解決因數據庫一次查詢數據量過大導致的內存溢出問題

    今天小編就為大家分享一篇完美解決因數據庫一次查詢數據量過大導致的內存溢出問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • 關于Cannot?resolve?com.microsoft.sqlserver:sqljdbc4:4.0報錯問題解決辦法

    關于Cannot?resolve?com.microsoft.sqlserver:sqljdbc4:4.0報錯問題解

    這篇文章主要給大家介紹了關于Cannot?resolve?com.microsoft.sqlserver:sqljdbc4:4.0報錯問題的解決辦法,這個是在pom文件中添加依賴出現(xiàn)報錯問題,需要的朋友可以參考下
    2024-02-02
  • springboot中通過jwt令牌校驗及前端token請求頭進行登錄攔截實戰(zhàn)記錄

    springboot中通過jwt令牌校驗及前端token請求頭進行登錄攔截實戰(zhàn)記錄

    這篇文章主要給大家介紹了關于springboot中如何通過jwt令牌校驗及前端token請求頭進行登錄攔截的相關資料,需要的朋友可以參考下
    2024-08-08

最新評論

营口市| 五指山市| 囊谦县| 高平市| 洪泽县| 定州市| 常州市| 汨罗市| 勐海县| 陵水| 隆德县| 淮南市| 中方县| 柳江县| 望都县| 抚顺县| 高唐县| 潼关县| 钟山县| 舞钢市| 射阳县| 通化县| 易门县| 堆龙德庆县| 江津市| 哈尔滨市| 海安县| 浪卡子县| 郴州市| 静乐县| 通山县| 内黄县| 罗城| 黄陵县| 大连市| 松潘县| 玉田县| 若尔盖县| 无为县| 徐闻县| 扎鲁特旗|