day 11 Redis

此文档是依据上课流程编写,更多细节及图片请参见刘老师的专栏

江哥的专栏

《cgb2008-京淘day11》

一. Redis客户端命令
  1. Hash类型

    i. 阐明

    能够用散列类型保留"对象"和属性值,个别在工作中存储的都是基于一个业务对象的数据。

    user{"name":"aa","age":5}

    ii. Hash类型命令

    hset user name aahset user age 5hget user age => "5"hgetall user => "name" "aa" "age" "5"hkeys user => "name" "age"
  2. List类型

    i. 阐明

    双端循环链表,能够从首尾两端拜访数据 L===R

    ii. List类型命令

    队列:lpush list 1 2 3 4 5 rpop ==> 1栈:lpush list 1 2 3 4 5 lpop ==> 5
  3. Set类型

    sadd set1 asadd set1 bscard set1sinter set1 set2sinterstore set3 set1 set2sismember set1 csmembers set1
  4. 事务命令

    Redis中的事务是弱事务,如果在分布式系统中无奈对事务进行管制。

    multiexecdiscard
二. 应用程序操作redis
  1. 整合入门案例

    i. 导入jar包

    <!--spring整合redis --><dependency>    <groupId>redis.clients</groupId>    <artifactId>jedis</artifactId></dependency><dependency>    <groupId>org.springframework.data</groupId>    <artifactId>spring-data-redis</artifactId></dependency>

    ii. 创立TestRedis测试类

    public class TestRedis {    @Test    //连贯服务:IP地址:端口    public void testSetGet() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129",6379);        jedis.flushAll(); //先清空redis缓存        //1.存取redis        jedis.set("好好学习", "天天向上");        String value = jedis.get("好好学习");        System.out.println(value);        //2.判断key是否存在        if(jedis.exists("好好学习")){            jedis.set("好好学习", "天天敲代码");        }else {            jedis.set("好好学习", "天天开心");        };        //3.为key增加超时工夫        jedis.expire("好好学习", 10);        Thread.sleep(2000);        System.out.println("残余存活工夫:"+jedis.ttl("好好学习"));        //4.撤销剩余时间        jedis.persist("好好学习");        System.out.println("撤销胜利");    }}
  2. 高级API

    i. 测试setnx()

    @Test//如果数据不存在,则批改数据public void testSetNx() throws InterruptedException {    Jedis jedis = new Jedis("192.168.126.129",6379);    jedis.set("key1", "aaa");    //如果key不存在则赋值    jedis.setnx("key1", "测试方法");    System.out.println(jedis.get("key1")); //"aaa"}

    ii. 测试setex()

    @Test//实现超时工夫的设定与赋值操作原子性public void testSetEx() throws InterruptedException {    Jedis jedis = new Jedis("192.168.126.129",6379);    jedis.set("key2", "bbb");    jedis.expire("key2", 3);    //数据超时之后肯定会被删除吗? 错!    //考点:为数据设定超时工夫时,切记满足原子性操作,否则会呈现key永远不能删除的景象    jedis.setex("key2", 3, "bbb");}

    iii. 测试SetParams

    @Test//如果key存在,则为其赋值并增加超时工夫public void testSet() throws InterruptedException {    Jedis jedis = new Jedis("192.168.126.129",6379);    /*if(jedis.exists("key3")){        jedis.setex("key3", 10, "cc");    }*/    //NX - 只有数据不存在时才会赋值 XX - 只有数据存在时才会赋值    //EX - 设置超时工夫:s PX - 设置超时工夫:ms    SetParams setParams = new SetParams();    setParams.xx().ex(10);    //将所有的操作采纳原子性的形式进行管制    jedis.set("key3", "ccc", setParams);}

    iv. 测试Hash

    @Testpublic 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"));}

    v. 测试List

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

    vi. 测试事务

    @Testpublic 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.set("c", "c");        //提交事务         transaction.exec();    }catch (Exception e){        //回滚事务        transaction.discard();    }}
三. SpringBoot整合redis
  1. 编写RedisConfig配置类

    @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);    }}
  2. 批改TestRedis测试类

    @SpringBootTestpublic class TestRedis {    @Autowired    private Jedis jedis;    ...}
四. 基于业务实现缓存
  1. ObjectMapperUtil实现

    i. 业务需要

    在业务中通常须要将业务对象

    ii. 入门案例-编写TestObjectMapper测试类

    public class TestObjectMapper {    //objectMapper入门案例    @Test    public void test01() 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);    }}
    //objectMapper入门案例@Testpublic void test02() throws JsonProcessingException {    List<ItemDesc> list = new ArrayList<>();    //1.将汇合转化为JSON    ItemDesc itemDesc = new ItemDesc();    itemDesc.setItemId(100L).setItemDesc("测试数据")            .setCreated(new Date()).setUpdated(itemDesc.getCreated());    ItemDesc itemDesc2 = new ItemDesc();    itemDesc2.setItemId(50L).setItemDesc("测试数据2")            .setCreated(new Date()).setUpdated(itemDesc.getCreated());    list.add(itemDesc);    list.add(itemDesc2);    ObjectMapper objectMapper = new ObjectMapper();    String json = objectMapper.writeValueAsString(list);    System.out.println(json);    //2.将JSON转化为汇合    List<ItemDesc> desc = objectMapper.readValue(json, list.getClass());    System.out.println(desc);}

    iii. 编辑ObjectMapperUtil工具API

    public class ObjectMapperUtil {    private static final ObjectMapper MAPPER = new ObjectMapper();    private static String toJSON(Object target){        try {            return MAPPER.writeValueAsString(target);        } catch (JsonProcessingException e) {            e.printStackTrace();            //将查看异样转化为运行时异样            throw new RuntimeException(e);        }    }    private static <T> T toObj(String json,Class<T> clazz){        try {            return MAPPER.readValue(json, clazz);        } catch (JsonProcessingException e) {            e.printStackTrace();            throw new RuntimeException(e);        }    }}
  2. 实现商品种类的缓存

    i. 编辑ItemCatController

    /* 业务需要:实现商品分类树形构造的展现    url: http://localhost:8091/item/cat/list    参数: id = 父级节点的id    返回值: List<EasyUITree>*/@RequestMapping("/list")public List<EasyUITree> showTree(Long id){    //临时只查问一级菜单信息    long pid = (id==null)?0L:id;    //数据库记录 ItemCat对象,页面中要的数据 EasyUITree    //须要将pojo对象转换为vo对象 get/set...    //List<EasyUITree> list = itemCatService.findAllCat(pid);    //return list;    return itemCatService.findItemCatCache(pid);}

    ii. 编辑ItemCatService/Impl

    /* 实现步骤:    1.先定义key ITEM_CAT_PARENT::0    2.先查问缓存        T - 通过获取缓存数据之后,将JSON转化为对象,之后返回        F - 应该查询数据库,之后将数据保留到redis中,默认30天超时 */@Autowired(required = false)private Jedis jedis;@Overridepublic List<EasyUITree> findItemCatCache(long pid) {    List<EasyUITree> treeList = new ArrayList<>();    //1.定义key    String key = "ITEM_CAT_PARENT::"+pid;    //2.    if(jedis.exists(key)){        String json = jedis.get(key);        System.out.println("==查问缓存==");        treeList =  ObjectMapperUtil.toObj(json,treeList.getClass());    }else {        //不存在        treeList = findAllCat(pid);        String json = ObjectMapperUtil.toJSON(treeList);        jedis.setex(key,7*24*60*60, json);        System.out.println("==查数据库==");    }    return treeList;}
  3. AOP实现Redis缓存

    i. AOP温习

    1) 利用AOP能够实现对办法(性能)的扩大,实现代码的解耦;

    2) 切面的组成因素:

    切面 = 切入点表达式 + 告诉办法

    3) 切入点表达式

    bean(bean的id) 拦挡bean的所有办法,是粗粒度的 --> 具体的某个类within(包名.类名) 扫描某个包下的某些类中的所有办法 com.jt.* 粗粒度的execution(返回值类型 包名.类名.办法名(参数列表)) 细粒度的 !!!@annotation(包名.注解名) 细粒度的

    4) 告诉办法

    before 指标办法执行前afterReturning 指标办法返回后afterThrowing 指标办法抛出异样后after 不论什么状况,最初都要执行around 指标办法执行前后都要执行

    前四种告诉类型个别用于记录程序运行的状态。如果要对程序运行的轨迹产生影响,首选around。

    ii. AOP入门案例 - 编写CacheAop

    @Aspect@Componentpublic class CacheAop {    //切面 = 切入点表达式+告诉办法    //表达式1: ItemCatServiceImpl类    //@Pointcut("within(com.jt.service.*)")    //.* 一级包下的类 ..* 所有子孙后代包中的类    //@Pointcut("execution(* com.jt.service..*.*(**))")    @Pointcut("bean(itemCatServiceImpl)") //l默认值类名首字母小写    public void pointcut(){}    @Before("pointcut()")    public void before(JoinPoint joinPoint){        //jointPoint代表连接点的对象-程序执行的办法实用于前四大类型        //1.获取指标对象        Object target = joinPoint.getTarget();        System.out.println(target);        //2.获取指标对象的门路 包名.类名.办法名        String className = joinPoint.getSignature().getDeclaringTypeName();        String methodName = joinPoint.getSignature().getName();        System.out.println("指标办法的门路: "+className+methodName);        //3.获取参数类型        System.out.println(Arrays.toString(joinPoint.getArgs()));    }    @Around("pointcut()")    public Object around(ProceedingJoinPoint joinPoint){        System.out.println("==盘绕告诉==");        Object data = null;        try {            data = joinPoint.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }        return data;    }}
作业:通过自定义注解@CacheFind实现AOP-redis缓存