发表于: 2017-07-17 22:40:04

1 1089


今天完成的事情:

上午学习了一下springcache,下午写代码,听大师兄讲课,晚上去华科跑了个步

缓存简介

缓存,我的理解是:让数据更接近于使用者;工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存);缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据。如CPU--L1/L2--内存--磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找。还有如用过Maven的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器找;还有如京东的物流为什么那么快?他们在各个地都有分仓库,如果该仓库有货物那么送货的速度是非常快的。

 

缓存命中率

即从缓存中读取数据的次数 与 总读取次数的比率,命中率越高越好:

命中率 = 从缓存中读取次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])

Miss率 = 没有从缓存中读取的次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])

 

这是一个非常重要的监控指标,如果做缓存一定要健康这个指标来看缓存是否工作良好;

 

缓存策略

Eviction policy

移除策略,即如果缓存满了,从缓存中移除数据的策略;常见的有LFU、LRU、FIFO:

FIFO(First In First Out):先进先出算法,即先放入缓存的先被移除;

LRU(Least Recently Used):最久未使用算法,使用时间距离现在最久的那个被移除;

LFU(Least Frequently Used):最近最少使用算法,一定时间段内使用次数(频率)最少的那个被移除;

TTL(Time To Live ):存活期,即从缓存中创建时间点开始直到它到期的一个时间段(不管在这个时间段内有没有访问都将过期)

TTI(Time To Idle):空闲期,即一个数据多久没被访问将从缓存中移除的时间。


文件结构

City

import java.io.Serializable;

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 + '\'' +
'}';
   }
}

CityRestController

import org.spring.springboot.domain.City;
import org.spring.springboot.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class CityRestController {

@Autowired
   private CityService cityService;


   @RequestMapping(value = "/api/city/{id}", method = RequestMethod.GET)
public City findOneCity(@PathVariable("id") Long id) {
return cityService.findCityById(id);
   }

@RequestMapping(value = "/api/city", method = RequestMethod.POST)
public void createCity(@RequestBody City city) {
cityService.saveCity(city);
   }

@RequestMapping(value = "/api/city", method = RequestMethod.PUT)
public void modifyCity(@RequestBody City city) {
cityService.updateCity(city);
   }

@RequestMapping(value = "/api/city/{id}", method = RequestMethod.DELETE)
public void modifyCity(@PathVariable("id") Long id) {
cityService.deleteCity(id);
   }
}

CityServiceImpl

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spring.springboot.dao.CityDao;
import org.spring.springboot.domain.City;
import org.spring.springboot.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;


@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;
   }

}

DAO层就不贴了

明天计划的事情:继续任务6

遇到的问题:用redis跑简单例子没遇到像家铭那样奇怪的情况

收获:听师兄讲课,那个IDEA的依赖树比较好用


返回列表 返回列表
评论

    分享到