Spring Boot學習之整合Redis實現緩存

1、什麼是緩存?
在互聯網場景下,尤其 2C 端大流量場景下,需要將一些經常展現和不會頻繁變更的數據,存放在存取速率更快的地方。緩存就是一個存儲器,在技術選型中,常用 Redis 作爲緩存數據庫。緩存主要是在獲取資源方便性能優化的關鍵方面。Redis 是一個高性能的 key-value 數據庫。
緩存的應用場景有哪些呢?比如常見的電商場景,根據商品 ID 獲取商品信息時,店鋪信息和商品詳情信息就可以緩存在 Redis,直接從 Redis 獲取。減少了去數據庫查詢的次數。
緩存更新策略
這裏我們使用的是 Cache Aside 策略,從三個維度:
失效:應用程序先從cache取數據,沒有得到,則從數據庫中取數據,成功後,放到緩存中。
命中:應用程序從cache中取數據,取到後返回。
更新:先把數據存到數據庫中,成功後,再讓緩存失效。

2、代碼實現
先看看pom.xml,添加redis依賴配置
 <!-- Spring Boot Reids 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>${spring-boot-starter-redis-version}</version>
        </dependency>
再在application.properties 應用配置文件,增加 Redis 相關配置
## 數據源配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 
## Mybatis 配置
mybatis.typeAliasesPackage=org.spring.springboot.domain
mybatis.mapperLocations=classpath:mapper/*.xml
 
## Redis 配置
## Redis數據庫索引(默認爲0)
spring.redis.database=0
## Redis服務器地址
spring.redis.host=127.0.0.1
## Redis服務器連接端口
spring.redis.port=6379
## Redis服務器連接密碼(默認爲空)
spring.redis.password=
## 連接池最大連接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
## 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
## 連接池中的最大空閒連接
spring.redis.pool.max-idle=8
## 連接池中的最小空閒連接
spring.redis.pool.min-idle=0
## 連接超時時間(毫秒)
spring.redis.timeout=0

新建城市對象
public class City implements Serializable {
 
    private static final long serialVersionUID = -1L;
 
    /**
     * 城市編號
     */
    private Long id;
 
    /**
     * 省份編號
     */
    private Long provinceId;
 
    /**
     * 城市名稱
     */
    private String cityName;
 
    /**
     * 描述
     */
    private String description;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public Long getProvinceId() {
        return provinceId;
    }
 
    public void setProvinceId(Long provinceId) {
        this.provinceId = provinceId;
    }
 
    public String getCityName() {
        return cityName;
    }
 
    public void setCityName(String cityName) {
        this.cityName = cityName;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    @Override
    public String toString() {
        return "City{" +
                "id=" + id +
                ", provinceId=" + provinceId +
                ", cityName='" + cityName + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}

城市接口業務處理
@Service
public class CityServiceImpl implements CityService {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(CityServiceImpl.class);
 
    @Autowired
    private CityDao cityDao;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    /**
     * 獲取城市邏輯:
     * 如果緩存存在,從緩存中獲取城市信息
     * 如果緩存不存在,從 DB 中獲取城市信息,然後插入緩存
     */
    public City findCityById(Long id) {
        // 從緩存中獲取城市信息
        String key = "city_" + id;
        ValueOperations<String, City> operations = redisTemplate.opsForValue();
 
        // 緩存存在
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            City city = operations.get(key);
 
            LOGGER.info("CityServiceImpl.findCityById() : 從緩存中獲取了城市 >> " + city.toString());
            return city;
        }
 
        // 從 DB 中獲取城市信息
        City city = cityDao.findById(id);
 
        // 插入緩存
        operations.set(key, city, 10, TimeUnit.SECONDS);
        LOGGER.info("CityServiceImpl.findCityById() : 城市插入緩存 >> " + city.toString());
 
        return city;
    }
 
    @Override
    public Long saveCity(City city) {
        return cityDao.saveCity(city);
    }
 
    /**
     * 更新城市邏輯:
     * 如果緩存存在,刪除
     * 如果緩存不存在,不操作
     */
    @Override
    public Long updateCity(City city) {
        Long ret = cityDao.updateCity(city);
 
        // 緩存存在,刪除緩存
        String key = "city_" + city.getId();
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            redisTemplate.delete(key);
 
            LOGGER.info("CityServiceImpl.updateCity() : 從緩存中刪除城市 >> " + city.toString());
        }
 
        return ret;
    }
 
    @Override
    public Long deleteCity(Long id) {
 
        Long ret = cityDao.deleteCity(id);
 
        // 緩存存在,刪除緩存
        String key = "city_" + id;
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            redisTemplate.delete(key);
 
            LOGGER.info("CityServiceImpl.deleteCity() : 從緩存中刪除城市 ID >> " + id);
        }
        return ret;
    }
 
}
首先這裏注入了 RedisTemplate 對象。聯想到 Spring 的 JdbcTemplate ,RedisTemplate 封裝了 RedisConnection,具有連接管理,序列化和 Redis 操作等功能。還有針對 String 的支持對象 StringRedisTemplate。

Redis 操作視圖接口類用的是 ValueOperations,對應的是 Redis String/Value 操作。還有其他的操作視圖,ListOperations、SetOperations、ZSetOperations 和 HashOperations 。ValueOperations 插入緩存是可以設置失效時間,這裏設置的失效時間是 10 s。

回到更新緩存的邏輯
a. findCityById 獲取城市邏輯:
如果緩存存在,從緩存中獲取城市信息
如果緩存不存在,從 DB 中獲取城市信息,然後插入緩存

b. deleteCity 刪除 / updateCity 更新城市邏輯:
如果緩存存在,刪除
如果緩存不存在,不操作







 





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