文章内容输出来源:拉勾教育Java高薪训练营;
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统带来很大压力。突然间大量的key失效了或redis重启,大量访问数据库,数据库崩溃,这时候就需要设置一个本地缓存作为二级缓存来解决这个问题。
本地缓存的应用场景:
数据从服务层读取,然后放到本地缓存中(Guava),如果出现超时或读取为空,则返回原来本地缓存的数据。这样如果出现分布式缓存redis挂掉等情况,依然可以从本地缓存中获取到数据,不会出现项目的瘫痪。
引入maven坐标
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
<version>1.4.7.RELEASEversion>
dependency>
<dependency>
<groupId>com.google.guavagroupId>
<artifactId>guavaartifactId>
<version>28.2-jreversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
具体逻辑实现部分,先从本地缓存Guava Cache中获取要查询的数据,如果没有则从redis中查询,如果redis 中也没有,则去mysql中查询,最后回写到redis,再回写到本地缓存Guava Cache中返回查询结果
@Service
public class PositionServiceImpl implements PositionService {
@Autowired
PositionMapper positionMapper;
@Autowired
RedisTemplate redisTemplate;
private static Cache<Object, Object> cache = CacheBuilder.newBuilder().expireAfterWrite(5,TimeUnit.SECONDS).build();
@Override
public List<Position> getHotPosition() throws ExecutionException {
//从guava本地缓存中获取数据,如果没有则从redis中回源
Object value = cache.get("position", new Callable() {
@Override
public Object call() throws Exception {
return getHotPositionListFromRedis();
}
});
if(value != null){
return (List<Position>)value;
}
return null;
}
@Override
public List<Position> getHotPositionListFromRedis() {
Object position = redisTemplate.opsForValue().get("position");
System.out.println("从redis中获取数据");
if(position == null) {
//从mysql中获取数据
List<Position> positionList = positionMapper.select(null);
System.out.println("从mysql中获取数据");
//同步至redis
redisTemplate.opsForValue().set("position",positionList);
System.out.println("同步至redis");
redisTemplate.expire("position",5, TimeUnit.SECONDS);
return positionList;
}
return (List<Position>)position;
}
}
调用查询接口
@RestController
@RequestMapping("position")
public class PositionController {
@Autowired
PositionService positionService;
@GetMapping
public List<Position> getHotPosition() throws ExecutionException {
List<Position> result = positionService.getHotPosition();
return result;
}
}
实体类
@Table(name = "t_position")
public class Position implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Mapper
@org.apache.ibatis.annotations.Mapper
public interface PositionMapper extends Mapper<Position> {
}
配置文件信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/lg?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=docker
logging.level.com.cache.cachework.dao.mapper=debug
spring.redis.cluster.nodes=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,127.0.0.1:7006
spring.redis.database=0
spring.redis.timeout=5000
然后把redis停掉,模拟宕机,继续请求
从本地缓存Guava Cache中获取到查询结果
工作几年,一直都没有去体系化的学习,很多东西没有复杂的工作场景经验,去年综合几家机构,最后还是决定报了拉勾的高薪训练营,在这里也是实实在在的学习到了很多,学完掌握程度也比之前深了很多,而且还有定期的内推,多了更多的机会,真的对我有了很大的帮助提升。