Java Redis緩存穿透/緩存雪崩/緩存擊穿,Redis分布式鎖實現秒殺,限購等


package com.example.redisdistlock.controller;

import com.example.redisdistlock.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class CacheController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate = null;

    @Autowired
    private RedisUtil redisUtil = null;

    /**
     * ****************************** 緩存穿透 ******************************
     * 緩存穿透,是指查詢一個數據庫一定不存在的數據。
     * 正常的使用緩存流程大致是,數據查詢先進行緩存查詢,
     * 如果key不存在或者key已經過期,再對數據庫進行查詢,
     * 並把查詢到的對象,放進緩存。如果數據庫查詢對象為空,則不放進緩存。
     * 災難現場:想象一下這個情況,如果傳入的參數為-1,會是怎么樣?這個-1,就是一定不存在的對象。就會每次都去查詢數據庫,
     *          而每次查詢都是空,每次又都不會進行緩存。假如有惡意攻擊,就可以利用這個漏洞,對數據庫造成壓力,甚至壓垮數據庫。
     * 解決方案:如果從數據庫查詢的對象為空,也放入緩存,只是設定的緩存過期時間較短,比如設置為60秒。
     */


    /**
     * ****************************** 緩存雪崩 ******************************
     * 是指在某一個時間段,緩存集中過期失效。此刻無數的請求直接繞開緩存,直接請求數據庫。
     * 災難現場:比如天貓雙11,馬上就要到雙11零點,很快就會迎來一波搶購,這波商品在23點集中的放入了緩存,假設緩存一個小時。
     * 那么到了凌晨24點的時候,這批商品的緩存就都過期了。而對這批商品的訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生周期性的壓力波峰。
     * 對數據庫造成壓力,甚至壓垮數據庫。
     */


    /**
     * ****************************** 緩存擊穿 ******************************
     * 是指一個key非常熱點,在不停的扛着大並發,大並發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大並發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。
     * 災難現場:比如某個爆款商品(這種爆款很難對數據庫服務器造成壓垮性的壓力。達到這個級別的公司沒有幾家的。)但我們也要做好防護方案
     * 解決方案:對爆款商品都是早早的做好了准備,讓緩存永不過期。即便某些商品自己發酵成了爆款,也是直接設為永不過期。
     */

    public  Object cacheBreakDown(){
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            Object zhangsan = redisUtil.get("zhangsan");
            //System.out.println("zhangsan" + zhangsan);

            /* 使用雙重驗證鎖解決高並發環境下的緩存穿透問題 */
            if (StringUtils.isEmpty(zhangsan)) { // 第一重驗證
                synchronized (this) {
                    zhangsan = redisUtil.get("zhangsan");
                    if (StringUtils.isEmpty(zhangsan)) { // 第二重驗證
                        System.out.println("查詢數據庫............");
                        // 緩存為空,則查詢數據庫將相關數據存儲到redis中
                        redisUtil.set("zhangsan", "張三",10); //10秒后過期
                    } else {
                        System.out.println("2 查詢緩存............");
                    }
                }
            } else {
                System.out.println("1 查詢緩存............");
            }

            map.put("success", true);

            ////entity實體類
            //User user = new User();
            //user.setUserId(1000);
            //user.setUserName("張三");
            //user.setAddress("深圳市南山區");
            //user.setMobile("13988886666");
            //redisUtil.set("userInfo", user.toString(), 10);  //10秒后過期自動刪除
            ////獲取顯示
            //String str = String.valueOf(redisUtil.get("userInfo"));
            //JSONObject jsonObj = new JSONObject(str);
            //map.put("userInfo", jsonObj.get("userId"));
        } catch (Exception e) {
            map.put("success", false);
            e.printStackTrace();
        } finally {
        }
        return map;
    }
}
    /**
     * Redis分布式並發鎖(針對業務場景:庫存超賣  秒殺  限購等)
     *
     * @return
     */
    @RequestMapping("/reductstore")
    @ResponseBody  //直接輸出字符串
    public String ReductStore() {
        System.out.println("訪問接口");
        String lockKey = "lock";

        // setnx   redisson
        RLock lock = redissonClient.getLock(lockKey);
        try {

            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));     lock.lock();
            if (stock > 0) {
                //業務邏輯減少庫存
                stringRedisTemplate.opsForValue().set("stock", (stock - 1) + "");
                System.out.println("扣減庫存成功,庫存stock:" + (stock - 1));
            } else {
                System.out.println("商品已售罄");
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return "OK";
    }

    /**
     * 單體式架構
     *
     * @return
     */
    @RequestMapping("/reduct")
    @ResponseBody  //直接輸出字符串
    public String Reduct() {
        //System.out.println("訪問接口");
        try {
            synchronized (this) {   //jvm核心技術
                int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
                if (stock > 0) {
                    //業務邏輯減少庫存
                    stringRedisTemplate.opsForValue().set("stock", (stock - 1) + "");
                    System.out.println("扣減庫存成功,庫存stock:" + (stock - 1));
                } else {
                    System.out.println("商品已售罄");
                }
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
        }
        return "OK";
    }

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM