1、缓存使用
为了系统性能的提升,我们一般都会将部分数据放入缓存中,加速访问。而 db 承担数据落 盘工作。
哪些数据适合放入缓存?
即时性、数据一致性要求不高的
访问量大且更新频率不高的数据(读多,写少)
举例:电商类应用,商品分类,商品列表等适合缓存并加一个失效时间(根据数据更新频率 来定),后台如果发布一个商品,买家需要 5 分钟才能看到新的商品一般还是可以接受的
data = cache.load(id);//从缓存加载数据 If(data == null){ data = db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;
注意:在开发中,凡是放入缓存中的数据我们都应该指定过期时间,使其可以在系统即使没有主动更新数据也能自动触发数据加载进缓存的流程。避免业务崩溃导致的数据永久不一致 问题。
2、整合 redis 作为缓存
1、引入 redis-starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2、配置 redis
1. redis: 2. host: 192.168.107.134 3. port: 6379
3、使用 RedisTemplate 操作 redis
@SpringBootTest(classes = GulimallProductApplication.class) @RunWith(SpringRunner.class) public class GUlimallProductApplicationTest { @Autowired StringRedisTemplate stringRedisTemplate @Test public void testRedis(){ ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); ops.set("hello","word"+ UUID.randomUUID().toString()); String v = ops.get("hello"); System.out.println(v); } }
4、切换使用 jedis
//todo 产生堆外内存溢出
//1)springboot2.0以后默认使用lettuce作为操作redis的客户端。他使用netty进行网络通信
//2)lettuce的bug导致netty堆外内存溢出 netty如果没有指定堆外内存,默认使用-Xmx
//可以通过-Dio.netty.maxDirectMemory进行设置
//解决方案:不能使用-Dio.netty.maxDirectMemory只去调大
//1)升级lettuce
//2)切换使用jedis
//lettuce jedis操作redis底层的客户端。spring再次封装成为redisTemplate
<!-- redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
修改业务代码
@Override public Map<String, List<Catelog2Vo>> getCatalogJson(){ //1.加入缓存逻辑 String catalogJSON = redisTemplate.opsForValue().get("catalogJSON"); if (StringUtils.isEmpty(catalogJSON)){ //2 缓存数据 缓存中没有 Map<String, List<Catelog2Vo>> catalogJsonForDb = getCatalogJsonForDb(); //3.查到的数据再放入缓存中,将对象转为json放进 String s = JSON.toJSONString(catalogJsonForDb); redisTemplate.opsForValue().set("catalogJSON",s); return catalogJsonForDb; } //转为我们指定的对象 Map<String, List<Catelog2Vo>> result = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() { }); return result; }
/** * 从数据库查询数据得到数据 * @return */ public Map<String, List<Catelog2Vo>> getCatalogJsonForDb() { /** * 1.将数据库的数据只查一次 */ List<CategoryEntity> selectList = baseMapper.selectList(null); //1.查出所有一级分类 List<CategoryEntity> level1Categorys = getLevel1Categorys(); //2封装数据 Map<String, List<Catelog2Vo>> parent_cid = level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> { //1.每一个的一级分类,查到这个一级分类的二级分类 List<CategoryEntity> categoryEntities = baseMapper.selectList(new QueryWrapper<CategoryEntity>() .eq("parent_cid", v.getCatId())); //2.封装上面的结果 List<Catelog2Vo> catelog2Vos = null; if (categoryEntities != null) { catelog2Vos = categoryEntities.stream().map(l2 -> { Catelog2Vo catelog2Vo = new Catelog2Vo( v.getParentCid().toString(), null, v.getName().toString(), v.getCatId().toString() ); //找出当前二级分类的三级分类分装成vo List<CategoryEntity> categoryEntities1 = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", l2.getCatId())); List<Catelog2Vo.Catelog3Vo> collect=null; if (categoryEntities1!=null){ collect = categoryEntities1.stream().map(l3 -> { Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo(l2.getCatId().toString(), l3.getName(), l3.getCatId().toString()); return catelog3Vo; }).collect(Collectors.toList()); } catelog2Vo.setCatalog3List(collect); return catelog2Vo; }).collect(Collectors.toList()); } return catelog2Vos; })); return parent_cid; }