1. 程式人生 > 其它 >redis 03 springboot 快取

redis 03 springboot 快取

Something before start

主要解決兩種快取場景
1、實時更新的快取 即一般的查詢時候,把記錄寫進快取。
2、不需要實時的快取 即不需要很準確的資料//比如使用者數量什麼的。對於這種情況,需要注意快取雪崩的問題。這裡是使用雙重檢測鎖來解決這個問題的。

快取雪崩:資料到期,大量請求湧入到資料庫

依賴

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

配置檔案

連線redis

有三種形式連線。另外注意配置redis的配置檔案

# 關閉保護模式
protected-mode no
# 把這個註釋掉,開啟外地連線
#bind 

單機

spring.redis.host=127.0.0.1
spring.redis.port=6379
#spring.redis.password=

哨兵模式叢集

# 這個mymaster 可以直接在sentinel.conf裡找到,可以更換成自己喜歡的hhhh
spring.redis.sentinel.master=mymaster
# 這裡展示的是多種寫法,多個哨兵
spring.redis.sentinel.nodes=locathost:26379,127.0.0.1:26380,locathost:26381
spring.redis.sentinel.password=

cluster叢集

# 連線redis叢集 //cluster模式
spring.redis.cluster.nodes=127.0.0.1:7006,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005
#spring.redis.password=

指定springboot快取形式

# 指定cache型別
spring.cache.type=redis
# 快取區域名稱 //隨便取都行 同時可以多快取空間
spring.cache.cache-names=realTimeCache

實體類序列化

很簡單,只要實現java的序列化介面就行Serializable


序列化簡單理解就是把一個物件轉化成字元流

public class Employee implements Serializable {
    private Integer id;
    private String name;
    private int age;
    //省略其他亂七八糟的東西

註解方式

怎麼確保快取準確性

每次更新資料的時候就清理所有的快取,在查詢的時候將資料時寫入快取。因為redis本身效能很高,所以不用擔心效能啥的。

啟動類開啟快取

@EnableCaching 開啟快取

@EnableCaching
@EnableTransactionManagement
@SpringBootApplication
public class RedisdemoApplication {

更新資料 清理快取

@CacheEvict: 放在更新(增刪改)資料的方法上

  1. value是前面配置的快取區域名稱。
  2. 當註解引數加上allEntries為true時,意思是說這個清除快取是清除當前value值空間下的所有快取資料。
    //更新資料 則 更新清理快取
    @CacheEvict(value = "realTimeCache", allEntries = true)
    @PostMapping("regist")
    public void registHandle(Employee employee) {
        employeeService.regist(employee);
    }

查詢資料 更新快取

@Cacheable:放在查詢的方法上

    //value:快取空間 key:鍵
    @Cacheable(value = "realTimeCache", key = "'emloyee_'+#id")
    @GetMapping("find")
    public Employee findHandle(int id) {
        return employeeService.findEmployeeById(id);
    }

API方式

什麼是雙重檢測鎖

第一次檢測:進入方法,如果有值則返回,如果取出來為空則開啟同步阻塞其他執行緒請求。
第二次檢測:進入同步執行緒之後,再次檢測是否有值,有則返回,無則將請求送到資料庫。
為什麼需要第二次檢測:第一取不到值的執行緒進入同步的時候,可能會有其他請求跑進來。第一個執行緒更新完之後,其他的執行緒就不許要重新更新,所以需要第二次檢測

實現程式碼

    //使用雙重檢測鎖 解決 熱點快取問題
    @GetMapping("count")
    public Integer countHandle() {
        //獲取redis操作物件 和count繫結 count即key
        BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");

        //從快取中獲得資料
        Object count = ops.get();

        if (count==null){
            //因為上鎖之後阻塞了 會有新的請求到這裡,所以需要上鎖後重新檢測保證後面來的不會擊穿
            //因為是單例 所以可以用this
            synchronized (this){
                count = ops.get();
                if (count==null){
                    count = employeeService.findEmployeeCount();
                    ops.set(count,10, TimeUnit.SECONDS);//存入 存活10秒
                }
            }
        }
        return (Integer)count;
    }

自動生成key

一樣是使用codeConfig方式。
然後就可以把註解裡的那個key刪掉了
注意這裡的para只適合一個引數的情況//其實寫一個迴圈就完事了
暫時懶得寫解釋,感性理解一下就好/

@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
    //自動生成key結構:類名_方法名_引數
    @Override
    public KeyGenerator keyGenerator() {
        return (target,method,params)->{
            String className = target.getClass().getName();
            String methodName =  method.getName();
            return className+"-"+methodName+"-"+params[0].toString();
        };
    }
}