1.系统优化策略
阐明:引入缓存机制能够无效的升高用户拜访物理设施的频次,从而进步响应速度.
2.如何设计缓存
1.缓存数据如何存储? 应该采纳什么样的数据结构呢? K-V key的唯一性
2.缓存数据的容量大小 应该动静保护缓存数据,将不须要的数据提前删除. LRU算法/LFU算法/随机算法/TTL算法
3.缓存数据保留到内存中,然而内存的特点断电即擦除. 定期将内存数据长久化(写入磁盘中)
4.单台缓存服务器性能有余,所以个别须要搭建集群(实现高可用).
5.应用C语言开发.
3.Redis缓存服务
3.1什么是Redis
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它能够用作数据库、缓存和消息中间件。 它反对多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 汇合(sets), 有序汇合(sorted sets) 与范畴查问, bitmaps, hyperloglogs 和 天文空间(geospatial) 索引半径查问。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘长久化(persistence), 并通过 Redis哨兵(Sentinel)和主动 分区(Cluster)提供高可用性(high availability)。
速度: 读: 11.2万/秒 写:8.6万/秒 50万/秒
3.2上传Redis
1).上传redis
2).解压redis服务
[root@localhost src]# tar -xvf redis-5.0.4.tar.gz
3).挪动文件/批改文件名称
3.3装置Redis
阐明:在Redis根目录中执行如下命令
1).make
2). make install
3.4 批改redis配置文件
批改redis根目录下的redis.conf文件
1).去除IP绑定
2).批改保护模式
3).开启后盾启动
4.Redis服务器命令
阐明: Redis服务在运行时,必须依赖于配置文件 redis.conf. 操作redis时最好在根目录中操作
1).启动redis
redis-server redis.conf
2).进入redis客户端
redis-cli -p 6379
ctrl + c 退出客户端
3).敞开redis服务器
redis-cli -p 6379 shutdown
办法二:
阐明: 如果操作的端口号是默认端口6379 则能够省略不写.
1).启动redis
redis-server redis.conf
2).进入redis客户端
redis-cli
3).敞开redis服务器
redis-cli shutdown
4.SpringBoot整合Redis
4.1 整合入门案例
4.1.1 导入jar包
`<!--spring整合redis redisTemplate Spring封装jedis高级API--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> </dependency>`
4.1.2 实现测试案例
4.2 测试根本命令
package com.jt.test;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import redis.clients.jedis.Jedis;import redis.clients.jedis.params.SetParams;//@SpringBootTestpublic class TestRedis { //链接服务: IP地址:端口 @Test public void testSetGet() throws InterruptedException { Jedis jedis = new Jedis("192.168.126.129",6379); jedis.flushAll(); //先清空redis缓存 //1.存取redis jedis.set("key1", "天天向上"); String value = jedis.get("key1"); System.out.println(value); //2.判断key是否存在 if(jedis.exists("key1")){ jedis.set("key1", "好好学习,天天向上"); }else{ jedis.set("key1", "天天开心"); } //3.为key增加超时工夫 jedis.expire("key1", 10); Thread.sleep(2000); System.out.println("残余存活工夫:"+jedis.ttl("key1")); //4.撤销残余超时工夫 jedis.persist("key1"); System.out.println("撤销胜利!!"); }}
4.2.1 setNx/setEx/set命令
/** * 需要: 如果数据不存在,则将数据批改 */ @Test public void testSetNx(){ Jedis jedis = new Jedis("192.168.126.129",6379); jedis.set("key1", "aaa"); //如果key不存在,则赋值 jedis.setnx("key1", "测试方法"); System.out.println(jedis.get("key1")); } /** * 需要: 实现超时工夫的设定与赋值操作的原子性. * 考点: 为数据设定超时工夫时,切记满足原子性要求. * 否则会呈现key永远不能删除的景象 */ @Test public void testSetEx(){ Jedis jedis = new Jedis("192.168.126.129",6379); /*jedis.set("key2", "bbb"); jedis.expire("key2", 3);*/ //???数据超时之后肯定会被删除吗??? 错的 jedis.setex("key2", 10, "bbb"); } /** * 需要: 如果数据存在时,才会批改数据,并且为数据增加超时工夫10秒(原子性). * 参数阐明: * NX: 只有数据不存在时,才会赋值. * XX: 只有数据存在时,才会赋值. * EX: 秒 * PX: 毫秒 */ public void testSet(){ Jedis jedis = new Jedis("192.168.126.129",6379); /* if(jedis.exists("key3")){ jedis.setex("key3",10 ,"ccc"); }*/ SetParams setParams = new SetParams(); setParams.xx().ex(10); //将所有的操作采纳原子性的形式进行管制 jedis.set("key3", "ccc", setParams); }
4.2.2 测试hash
/** * HASH测试 */ @Test public void testHash(){ Jedis jedis = new Jedis("192.168.126.129",6379); jedis.hset("person", "id", "100"); jedis.hset("person", "name", "tomcat猫"); System.out.println(jedis.hgetAll("person")); }
4.2.3 测试List
/** * LIST汇合测试 */ @Test public void testList(){ Jedis jedis = new Jedis("192.168.126.129",6379); jedis.lpush("list", "1","2","3","4"); String value = jedis.rpop("list"); System.out.println(value); }
4.2.4 测试事务
/** * Set汇合测试 * 1. sadd 新增元素 * 2. SCARD 获取元素数量 * 3. SINTER key1 key2 获取元素的交加 * 4. SMEMBERS set 获取汇合元素 * demo本人补一下 */ @Test public void testMulti(){ Jedis jedis = new Jedis("192.168.126.129",6379); //开启事务 Transaction transaction = jedis.multi(); try { transaction.set("a", "a"); transaction.set("b", "b"); //提交事务 transaction.exec(); }catch (Exception e){ //回滚事务 transaction.discard(); } }
5.SpringBoot整合Redis的理论使用
5.1 编辑properties配置文件
5.2 编辑配置类
package com.jt.config;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import redis.clients.jedis.Jedis;@Configuration//标识是个配置类,个别与@Bean注解连用@PropertySource("classpath:/properties/redis.properties")public class RedisConfig { @Value("${redis.host}") private String host; @Value("${redis.port}") private Integer port; @Bean public Jedis jedis(){ return new Jedis(host,port); }}
6.ObjectMapperUtil实现
6.1 业务需要
阐明:在业务中通常须要将业务对象转化为JSON数据.须要通过工具API进行手动的转化.
6.2 入门案例
public class TestObjectMapper { //objectMapper入门案例 //2. 将JSON转化为对象 @Test public void testObject() throws JsonProcessingException { //1. 将对象转化为JSON ItemDesc itemDesc = new ItemDesc(); itemDesc.setItemId(100L) .setItemDesc("我是一个测试数据") .setCreated(new Date()) .setUpdated(itemDesc.getCreated()); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(itemDesc); System.out.println(json); //2.将JSON转化为对象 ItemDesc desc = objectMapper.readValue(json, ItemDesc.class); System.out.println(desc); } @Test public void testList() throws JsonProcessingException { List<ItemDesc> list = new ArrayList<>(); ItemDesc itemDesc = new ItemDesc(); itemDesc.setItemId(100L).setItemDesc("我是一个测试数据").setCreated(new Date()).setUpdated(itemDesc.getCreated()); ItemDesc itemDesc2 = new ItemDesc(); itemDesc2.setItemId(200L).setItemDesc("我是一个测试数据").setCreated(new Date()).setUpdated(itemDesc.getCreated()); list.add(itemDesc); list.add(itemDesc2); //1. 将对象转化为JSON ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(list); System.out.println(json); //2.将JSON转化为对象 List<ItemDesc> list2 = objectMapper.readValue(json,list.getClass()); System.out.println(list2); }}
6.3 编辑ObjectMapperUtil
public class ObjectMapperUtil { private static final ObjectMapper MAPPER = new ObjectMapper(); public static String toJSON(Object target){ try { return MAPPER.writeValueAsString(target); } catch (JsonProcessingException e) { e.printStackTrace(); //将查看异样转化为运行时异样. throw new RuntimeException(e); } } public static <T> T toObject(String json,Class<T> targetClass){ try { return MAPPER.readValue(json, targetClass); } catch (JsonProcessingException e) { e.printStackTrace(); throw new RuntimeException(e); } }}
7.实现商品分类缓存操作
7.1 编辑ItemController
/** * 业务需要: 实现商品分类树形构造展示 * url地址: http://localhost:8091/item/cat/list * 参数: id= 父级节点的ID * 返回值: List<EasyUITree> */ @RequestMapping("/list") public List<EasyUITree> findItemCatList(Long id){ //临时只查问一级商品分类信息 long parentId = (id==null?0:id); //return itemCatService.findItemCatList(parentId); return itemCatService.findItemCatCache(parentId); }
7.2 编辑ItemService
package com.jt.service;import com.baomidou.mybatisplus.core.conditions.query.Query;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.jt.mapper.ItemCatMapper;import com.jt.pojo.ItemCat;import com.jt.util.ObjectMapperUtil;import com.jt.vo.EasyUITree;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import redis.clients.jedis.Jedis;import java.util.ArrayList;import java.util.List;@Servicepublic class ItemCatServiceImpl implements ItemCatService{ @Autowired private ItemCatMapper itemCatMapper; @Autowired(required = false) //相似于懒加载 private Jedis jedis; @Override public ItemCat findItemCatById(Long itemCatId) { return itemCatMapper.selectById(itemCatId); } /** * 1.依据parentId 查问子级目录信息 * 2.获取ItemCatList汇合,之后将List汇合转化为VOList汇合 * 3.返回数据 * @param parentId * @return */ @Override public List<EasyUITree> findItemCatList(long parentId) { QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("parent_id", parentId); List<ItemCat> catList = itemCatMapper.selectList(queryWrapper); //2 list汇合转化 List<EasyUITree> treeList = new ArrayList<>(catList.size()); for (ItemCat itemCat : catList){ long id = itemCat.getId(); String text = itemCat.getName(); String state = itemCat.getIsParent()?"closed":"open"; //是父级,默认应该closed EasyUITree easyUITree = new EasyUITree(id, text, state); treeList.add(easyUITree); } return treeList; } /** * 实现步骤: * 1.先定义key ITEM_CAT_PARENT::0 * 2.先查问缓存 * 有 true 获取缓存数据之后,将JSON转化为对象 之后返回 * 没有 false 应该查询数据库, 之后将数据保留到redis中. 默认30天超时. * * @param parentId * @return */ @Override public List<EasyUITree> findItemCatCache(long parentId) { Long startTime = System.currentTimeMillis(); List<EasyUITree> treeList = new ArrayList<>(); //1.定义key String key = "ITEM_CAT_PARENT::"+parentId; //2.从缓存中获取对象 if(jedis.exists(key)){ //存在 间接获取缓存数据,之后转化为对象 String json = jedis.get(key); treeList = ObjectMapperUtil.toObject(json,treeList.getClass()); System.out.println("查问redis缓存,获取数据"); long endTime = System.currentTimeMillis(); System.out.println("耗时:"+(endTime-startTime)+"毫秒"); }else{ //不存在 应该先查询数据库,之后将数据保留到缓存中. treeList = findItemCatList(parentId); String json = ObjectMapperUtil.toJSON(treeList); jedis.setex(key, 7*24*60*60, json); System.out.println("查询数据库获取后果"); long endTime = System.currentTimeMillis(); System.out.println("耗时:"+(endTime-startTime)+"毫秒"); } return treeList; }}