欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

cgb2008-京淘day11

程序员文章站 2022-03-10 15:39:31
1.SpringBoot整合Redis2.利用AOP实现redis缓存业务...

1. SpringBoot整合Redis

1.1 整合入门案例

1.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>

1.1.2 完成测试案例

cgb2008-京淘day11

1.1.3 测试基本命令

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;

//@SpringBootTest
public 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("撤销成功!!");
    }


}

1.1.4 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);
    }

1.1.5 测试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"));
    }

1.1.6 测试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);
    }

1.1.7 测试事务

/**
     * 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();
        }
    }

1.2 SpringBoot整合Redis

1.2.1 编辑properties配置文件

cgb2008-京淘day11

1.2.2 编辑配置类

cgb2008-京淘day11

1.3 ObjectMapperUtil实现

1.3.1 业务需求

说明:在业务中通常需要将业务对象转化为JSON数据.需要通过工具API进行手动的转化.

1.3.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);
    }

}

1.3.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);
        }
    }
}

1.4 实现商品分类缓存操作

1.4.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);
    }

1.4.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;

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

2.AOP实现Redis缓存

2.1 AOP作用

利用AOP可以实现对方法(功能)的扩展.实现代码的解耦.

2.2 切面组成要素

切面 = 切入点表达式 + 通知方法

2.2.1 切入点表达式

1).bean(bean的ID) 拦截bean的所有的方法 具体的某个类 粗粒度的.
2).within(包名.类名) 扫描某个包下的某个类 com.jt.* 粗粒度的.
3).execution(返回值类型 包名.类名.方法名(参数列表)) 细粒度的
4).@annotation(包名.注解名) 细粒度的

2.2.2 通知方法

说明: 通知相互之间没有顺序可言. 每个通知方法都完成特定的功能,切记AOP的通知方法与目标方法之间的顺序即可.
1).before 目标方法执行前
2).afterReturning 目标方法执行后
3).afterThrowing 目标方法执行抛出异常时执行.
4).after 不管什么情况,最后都要执行的.
上述四大通知类型,一般用来记录程序的运行状态的.(监控机制)

5).around 目标方法执行前后都要执行.
如果要对程序的运行轨迹产生影响,则首选around.

2.2.3 AOP入门案例

@Aspect     //标识我是一个切面
@Component  //将对象交给spring容器管理  cacheAOP
public class CacheAOP {

    //切面 = 切入点表达式 + 通知方法
    //表达式1: bean(itemCatServiceImpl)  ItemCatServiceImpl类
    //@Pointcut("bean(itemCatServiceImpl)")
    //@Pointcut("within(com.jt.service.*)")
        // .* 一级包下的类   ..* 所有子孙后代的包和类
        //返回值类型任意, com.jt.service包下的所有类的add方法参数类型任意类型
        //写参数类型时注意类型的大小写
    @Pointcut("execution(* com.jt.service..*.*(..))")
    public void pointcut(){

    }
    /**
     *
     * joinPoint代表连接点对象,一般适用于前四大通知类型(除around之外的)
     *        客人                         路人
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        //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;
    }

}

2.3 作业

通过自定义注解@CacheFind完成缓存操作.
cgb2008-京淘day11

本文地址:https://blog.csdn.net/qq_16804847/article/details/110850266

相关标签: 正课 redis