redis的使用

Redis安装

上传安装文件
在这里插入图片描述
解压redis

tar -zxvf  redis-5.0.5.tar.gz

修改redis文件目录

在这里插入图片描述
安装Redis

1.make 2.make install
在这里插入图片描述
修改redis配置文件

命令:vim redis.conf

1.关闭IP绑定
在这里插入图片描述
2.关闭保护模式
在这里插入图片描述
3.开启后台启动
在这里插入图片描述
Redis服务器操作命令

1.redis-server redis.conf 默认条件下 前台启动

2.redis-cli  -p   6379   进入客户端        exit/quit/ctrl+c   退出客户端

3.redis-cli  -p   6379  shutdown   或者  ps -ef    |grep   redis     kill    -9   PID号      关闭redis服务器.

Redis入门案例

添加jar包文件

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

操作String类型

public class TestRedis {
    
    /**
     * 测试String数据类型
     * 1.链接redis服务器    192.168.126.129:6379
     * 2.通过命令操作redis.
     * 
     * 问题说明:程序链接不通   检查redis配置文件 是否修改3项.
     * 修改之后重启redis服务器.
     */
    private Jedis jedis;
    
    @BeforeEach     //当执行test测试方式时,首先执行该操作
    public void init() {
        
        //jedis对象实例化
        jedis = new Jedis("192.168.126.129", 6379);
    }
    
    @Test
    public void testString() {
        //Jedis jedis = new Jedis("192.168.126.129", 6379);
        
        //1.利用set方法实现redis赋值
        jedis.set("jedis","天天都需要爱,心思由你猜!!!!!");
        String value = jedis.get("jedis");
        System.out.println(value);
        
        //2.测试是否还有某个key
        Boolean flag = jedis.exists("a");
        System.out.println(flag);
        
        //3.动态获取value的长度.
        System.out.println(jedis.strlen("jedis"));
        
        //4.动态获取所有key 
        Set<String>   sets = jedis.keys("*");
        System.out.println(sets);
    }
    
    /**
     * 需求:
     *  1.如果key存在则不允许修改数据.
     */
    @Test
    public void testString_NX() {
        jedis.flushAll();   //清空redis
        //测试1:
        //jedis.set("a","100");
        //jedis.set("a","1000");  redis对同样的数据进行操作时,其实做的是修改操作
        
        //测试2:
        //jedis.set("a", "100");
        /*if(!jedis.exists("a")) {
            jedis.set("a", "2000");
        }*/
        
        //测试3: jedis.setNX();   只有数据不存在时,才能赋值成功!!
        jedis.setnx("a","100");     //成功
        jedis.setnx("a","1000");    //失败
        System.out.println(jedis.get("a"));
    }
    
    
    /**
     * 需求:赋值同时为数据添加超时时间
     * @throws InterruptedException 
     * 说明:如果将赋值操作和超时的设定分开写,则丧失了操作的原子性.
     * 原子性: 要求数据同时生效/同时不生效.
     */
    @Test
    public void testString_EX_PX() throws InterruptedException {
        /*jedis.set("b", "100");
        //int a = 1/0;  //程序报错了.
        jedis.expire("b", 10);  //为key添加10秒超时时间
        Thread.sleep(2000);
        System.out.println("剩余超时时间:"+jedis.ttl("b")+"秒");*/
        
        //ex方法时间单位 秒
        jedis.setex("b", 10, "100");    //要么同时成功,要么同时失败
        //赋值毫秒
        jedis.psetex("c", 2000, "100");
        
    }
    
    
    /**
     * 需求3:
     *  1.要求赋值同时添加超时时间    操作满足原子性要求 
     *  2.如果key不存在时才能赋值.  
     *  目标:  ex  nx方法同时操作
     * 
     * XX: 只有key存在时才会赋值.
     * NX: 如果key不存在时才会赋值
     * EX: 添加超时时间 单位秒
     * PX: 添加超时时间单位毫秒
     */
    @Test
    public void testStringSet() {
        SetParams setParams = new SetParams();
        setParams.xx().ex(10);
        jedis.set("c", "200", setParams);
        jedis.set("c", "2000", setParams);
        System.out.println(jedis.get("c"));
    }
    
}

操作Hash类型

//一般hash方式使用与业务数据的调用 {item:  item详情 ,商品规格信息}
    //如果业务数据需要嵌套可以采用hash方式进行存储.
    @Test
    public void  testHash() {
        Map<String,String> hashMap = new HashMap<String, String>();
        hashMap.put("id", "101");       //更新操作
        hashMap.put("name", "人类");
        Long result = jedis.hset("person", hashMap);
        System.out.println(result);
        
        jedis.hset("dog", "id", "101");
        jedis.hset("dog", "name", "jerry");
        jedis.hset("dog", "age", "2");
        System.out.println(jedis.hgetAll("dog"));
    }

操作List类型

/**
     * 操作list集合
     * 
     */
    @Test
    public void testList() {
        
        jedis.lpush("myList", "1","2","3","4");
        String value = jedis.rpop("myList");
        System.out.println(value);
    }

事务控制

@Test
    public void testTx() {
        Transaction transaction = jedis.multi();    //开启事务
        try {
            transaction.set("a", "a");
            transaction.set("b", "b");
            int a = 1/0;
            transaction.exec(); //事务提交
            System.out.println("事务提交成功");
        } catch (Exception e) {
            e.printStackTrace();
            transaction.discard();  //事务回滚
            System.out.println("事务提交失败");
        }
    }

SpringBoot整合Redis

编辑properties文件

#配置第一个台Redis
redis.node=192.168.126.129:6379

配置类实现

@Configuration  //标识配置类
@PropertySource("classpath:/properties/redis.properties") //spring容器去加载配置文件
public class RedisConfig {
    
    @Value("${redis.node}")
    private String node;    //标识redis节点    host:port
    
    @Bean   //方法名称当作key,返回值结果当作value 存储到Spring容器中
    public Jedis jedis() {
        
        String[] array = node.split(":");
        String host = array[0]; //动态获取IP地址
        int port = Integer.parseInt(array[1]);  //获取端口号
        return new Jedis(host, port);
    }
}

Redis实现商品分类缓存

JAVA对象和JSON串转化

public class TestObjectMapper {
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 该测试类,主要解决了对象与JSON串之间的转化的问题
     * 1.对象转化为JSON
     * @throws JsonProcessingException 
     */
    @Test
    public void ObjectToJSON() throws JsonProcessingException {
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("测试对象转化!!!")
                .setCreated(new Date()).setUpdated(new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        //将对象转化为JSON
        String json = objectMapper.writeValueAsString(itemDesc);
        System.out.println(json);
        
        //将JSON转化为对象
        ItemDesc itemDesc2 = objectMapper.readValue(json, ItemDesc.class);
        System.out.println(itemDesc2);
    }
    
    
    /**
     * list集合与JSON转化
     * @throws JsonProcessingException 
     */
    @SuppressWarnings("unchecked")
    @Test
    public void listToJSON() throws JsonProcessingException{
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("测试对象转化!!!")
                .setCreated(new Date()).setUpdated(new Date());
        ItemDesc itemDesc2 = new ItemDesc();
        itemDesc2.setItemId(1000L).setItemDesc("测试对象转化!!!")
                .setCreated(new Date()).setUpdated(new Date());
        
        List<ItemDesc> list = new ArrayList<ItemDesc>();
        list.add(itemDesc);
        list.add(itemDesc2);
        
        String json = objectMapper.writeValueAsString(list);
        System.out.println(json);
        
        List<ItemDesc> list2 = 
                objectMapper.readValue(json, list.getClass());
        System.out.println(list2);
    }
    
}

编辑ObjectMapperUtil工具API

public class ObjectMapperUtil {
    
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    //1.java对象转化为json
    public static String toJSON(Object object) {
        
        try {
            return MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    
    //2.json串转化为对象 要求:用户传递什么类型,则可以动态的返回什么对象 
    //问题:能否确定用户传递什么类型的数据??????   确定不了的数据可以使用泛型
    //<T> 定义一个泛型对象     T:泛型引用
    public static <T> T toObject(String json,Class<T> targetClass) {
        
        if(StringUtils.isEmpty(json)) {
            //如果为null返回空指针异常
            System.out.println("json参数为null,请检查数据!!!!");
            throw new NullPointerException();
        }
        try {
            return MAPPER.readValue(json,targetClass);
        } catch (JsonProcessingException e) {
            
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

商品分类缓存实现

编辑ItemCatController

@RequestMapping("/list")
    public List<EasyUITree> findItemCatListByParentId
    (@RequestParam(name="id",defaultValue="0")Long parentId){
        //根据parentId查询数据库.
        //return itemCatService.findItemCatListByParentId(parentId);
        
        //执行缓存的业务操作
        return itemCatService.findItemCatCache(parentId);
    }

编辑ItemCatService

/**
     * 具体实现步骤:
     *  1.动态的拼接key=类名.方法名::参数列表
     *  2.根据key查询redis服务器.
     *  3.判断返回值是否有值.
     *  4.如果查询的结果为null,则表示redis服务器没有数据.应该查询数据库.
     *      5.将数据库记录通过工具API实现json转化.之后保存到redis中.
     *  6.如果查询的结果不为null,则表示redis服务器中有数据.可以将JSON直接转化为对象.
     */
    @Override
    public List<EasyUITree> findItemCatCache(Long parentId) {
        Long start = System.currentTimeMillis();    //记录开始时间
        //1.动态生成KEY
        String key = "ItemCatServiceImpl.findItemCatCache::"+parentId;
        //2.根据key获取缓存数据
        String value = jedis.get(key);
        List<EasyUITree> treeList = new ArrayList<EasyUITree>();
        //3.判断value的有效性.
        if(StringUtils.isEmpty(value)) {
            //4.如果为null,则表示应该查询数据库.
            treeList = findItemCatListByParentId(parentId);
            Long end = System.currentTimeMillis();
            //5.将数据保存到redis中
            String json = ObjectMapperUtil.toJSON(treeList);
            jedis.set(key, json);
            System.out.println("第一次查询,执行数据库操作耗时:"+(end-start)+"毫秒");
        }else {
            //6.redis中有缓存记录,需要将redis中的数据转化之后返回.
            treeList = ObjectMapperUtil.toObject(value,treeList.getClass());
            Long end = System.currentTimeMillis();
            System.out.println("redis实现缓存查询!!!! 耗时:"+(end-start)+"毫秒");
        }
        
        return treeList;
    }

缓存优化AOP策略

自定义注解CacheFind

@Target(ElementType.METHOD)         //表示当前注解对方法有效
@Retention(RetentionPolicy.RUNTIME) //运行时有效
public @interface CacheFind {
    //1.可以由用户自己指定     2.动态生成key
    String key() default "";
    //2.指定key的超时时间   默认条件下 当前key永不超时
    int secondes() default 0;
}

编辑缓存AOP

//主要目的实现Redis缓存
@Component      //将该对象交给spring容器管理
@Aspect         //表示该类是一个切面
public class CacheAOP {
    
    @Autowired
    private Jedis jedis;
    /**
     * 通知选择: 控制目标方法执行  选用环绕通知.
     * 切入点表达式定义:   拦截CacheFind注解
     * 规则:ProceedingJoinPoint 必须位于第一位
     */
    
    @Around("@annotation(cacheFind)")       //动态获取注解的参数
    public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) {
        //1.动态生成key
        String key = getKey(joinPoint,cacheFind);
        
        //2.根据key查询redis服务器
        String value = jedis.get(key);
        
        //3.判断value是否有数据
        Object result = null;
        if(StringUtils.isEmpty(value)) {
            //用户第一次查询缓存,则需要执行目标方法
            try {
                result = joinPoint.proceed();
                //将result转化为JSON数据.
                String json = ObjectMapperUtil.toJSON(result);
                //将数据保存到redis缓存中
                if(cacheFind.secondes()>0) {
                    //动态获取缓存超时时间
                    int seconds = cacheFind.secondes();
                    jedis.setex(key, seconds, json);
                }else {
                    jedis.set(key, json);//不需要设定超时时间
                }
                System.out.println("redis查询数据库成功!!!!");
            } catch (Throwable e) {
                e.printStackTrace();
                throw new RuntimeException();
            }
        }else {
            //表示redis中有数据 应该通过缓存动态的获取数据.
            //targetClass:方法返回值的参数类型???? JAVA基础中反射概念 用法
            //利用SpringAOP中的工具API动态获取返回值类型
            MethodSignature methodSignature = 
                            (MethodSignature) joinPoint.getSignature();
            Class<?> returnType = methodSignature.getReturnType();
            result = ObjectMapperUtil.toObject(value, returnType);
            System.out.println("查询redis缓存成功!!!!");
        }
        
        return result;
    }
    
    /**
     * 策略:
     *  1.如果用户自己指定了key,则使用用户的.
     *  2.如果用户没有指定key ,则动态生成.
     *    类名.方法名::参数值
     * @param joinPoint
     * @param cacheFind
     * @return
     */
    private String getKey(ProceedingJoinPoint joinPoint, CacheFind cacheFind) {
        //1.检查用户是否指定key
        String key = cacheFind.key();
        if(!StringUtils.isEmpty(key)) {
            //说明用户自己指定
            return key;
        }
        
        //2.用户自己没有指定,需要动态生成.
        String className = joinPoint.getSignature().getDeclaringTypeName();
        //获取方法名称
        String methodName = joinPoint.getSignature().getName();
        //获取方法中的参数
        Object[] args = joinPoint.getArgs();
        //将整个参数转化为字符串,之后当做key
        String strArgs = Arrays.toString(args); 
        
        return className+"."+methodName+"::"+strArgs;
    }
}   

SpringBoot整合Redis集群

测试API

@Test
    public void test01() {
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        nodes.add(new HostAndPort("192.168.126.129",7000));
        nodes.add(new HostAndPort("192.168.126.129",7001));
        nodes.add(new HostAndPort("192.168.126.129",7002));
        nodes.add(new HostAndPort("192.168.126.129",7003));
        nodes.add(new HostAndPort("192.168.126.129",7004));
        nodes.add(new HostAndPort("192.168.126.129",7005));
        //操作redis集群的API
        JedisCluster jedisCluster = new JedisCluster(nodes);
        jedisCluster.set("redis", "redis集群配置!!!!!");
        String value = jedisCluster.get("redis");
        System.out.println("动态获取redis结果信息:"+value);
    }

编辑properties文件

redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005

编辑RedisConfig配置类

@Configuration  //标识配置类
@PropertySource("classpath:/properties/redis.properties") //spring容器去加载配置文件
public class RedisConfig {
    
    @Value("${redis.nodes}")
    private String nodes;       //node,node,node
    
    /**
     * SpringBoot整合redis集群
     * 1.为redis的节点动态赋值.
     * 2.编辑配置类 返回JedisCluster对象
     */
    @Bean
    @Scope("prototype")
    public JedisCluster jedisCluster() {
        Set<HostAndPort> setNodes = new HashSet<HostAndPort>();
        String[] nodeArray = nodes.split(",");
        for (String node : nodeArray) {
            String[] hNode = node.split(":");
            String host = hNode[0];
            int port = Integer.parseInt(hNode[1]);
            setNodes.add(new HostAndPort(host, port));
        }
        return new JedisCluster(setNodes);
    }
    
}

编辑CacheAOP

修改AOP中的属性注入
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值