简单记录,以下操作均已在IDEA中手动敲了一边。。。

1、Java操作Redis

创建maven项目,引入jedis依赖,把junit也引一下

        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
<!--            <scope>test</scope>-->

基本操作,连接redis服务、选择库等:

package com.jin.test;

import redis.clients.jedis.Jedis;

import java.util.Set;

/**
 * @author jinyunlong
 * @date 2021/10/26 9:13
 * @profession ICBC锅炉房保安
 */

//测试redis连接
public class TestRedis {
    public static void main(String[] args) {
        //创建jedis客户端对象
        Jedis jedis = new Jedis("192.168.6.138",7000);

        //选择使用一个库  默认:使用 0号库
        jedis.select(0);

        //获取redis中所有key信息
        Set<String> keys = jedis.keys("*");
        keys.forEach(key -> System.out.println("key = " + key));

        //操作库相关
        jedis.flushDB(); //清空当前库
        jedis.flushAll(); //清空所有库

        //释放资源
        jedis.close();

    }
}

操作key相关的一些api:

package com.jin.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

/**
 * @author jinyunlong
 * @date 2021/10/26 9:30
 * @profession ICBC锅炉房保安
 */
public class TestKey {
    private Jedis jedis;

    @Before
    public void before(){
        this.jedis = new Jedis("192.168.6.138",7000);
    }

    @After
    public void after(){
        jedis.close();
    }

    //测试key相关
    @Test
    public void testKey(){
        //删除一个key
//        jedis.del("name");

        //删除多个key
//        jedis.del("name","age");

        //判断一个key是否存在exists
        Boolean aBoolean = new Boolean(jedis.exists("name"));
        System.out.println(aBoolean);

        //设置一个key超时时间 expire pexpire
//        Long age = jedis.expire("age", 100);
//        System.out.println(age);

        //查看一个key超时时间 ttl
        Long ttl = jedis.ttl("age");
        System.out.println(ttl);

        //随机获取一个key
        String s = jedis.randomKey();
        System.out.println(s);
        //修改key名称
//        String rename = jedis.rename("hhhh","aaaa");
//        System.out.println(rename);

        //查看key对应值的类型
        String name = jedis.type("age");
        System.out.println(name);

    }
}

操作String型的相关api:

package com.jin.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;

/**
 * @author jinyunlong
 * @date 2021/10/26 9:30
 * @profession ICBC锅炉房保安
 */
public class TestString {
    private Jedis jedis;

    @Before
    public void before(){
        this.jedis = new Jedis("192.168.6.138",7000);
    }

    @After
    public void after(){
        jedis.close();
    }

    //测试String相关
    @Test
    public void testString() {
        //set
        jedis.set("name","小金");
        //get
        String name = jedis.get("name");
        System.out.println(name);
        //mset
        jedis.mset("content","割让大苏打","address","大型");
        //mget
        List<String> mget = jedis.mget("name", "content", "address");
        mget.forEach(v -> System.out.println("v = " + v));
        //getset 拿原始值再设置新值
        String set = jedis.getSet("name", "小明");
        System.out.println(set);

        Long strlen = jedis.strlen("content");
        System.out.println(strlen);
    }
}

操作List型的相关api:

package com.jin.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;

/**
 * @author jinyunlong
 * @date 2021/10/26 9:30
 * @profession ICBC锅炉房保安
 */
public class TestList {
    private Jedis jedis;

    @Before
    public void before(){
        this.jedis = new Jedis("192.168.6.138",7000);
    }

    @After
    public void after(){
        jedis.close();
    }

    //测试List相关
    @Test
    public void testList() {
        //lpush
        jedis.lpush("names1","张三","李四","王五");

        //rpush
        jedis.rpush("names1","kkk","aaa","www");

        //lrange
        List<String> names = jedis.lrange("names1", 0, -1);
        names.forEach(list -> System.out.println("list = " + list));

        //lpop rpop
        String names1 = jedis.lpop("names1");
        System.out.println(names1);

        //llen
        Long names11 = jedis.llen("names1");
        System.out.println(names11);

        //etc、、、

    }
}

由此看出,关于key、string、list,还有set、zset、hash型的数据操作,都被jedis封装成api了,只需要直接调用方法就行了。set、zset、hash的操作就不贴了,调用的方法名和客户端操作指令基本是一样的。

2、SpringBoot整合Redis

注意:具体使用哪个类要看业务场景需要使用的数据类型,建议使用RedisTemplate然后自定义key、value的数据类型,一般key为String,value为Object。注意使用RedisTemplate的话,对象必须实现对象序列化接口。

1.PNG

引依赖,写配置:

        <!--引入依赖 spring data redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

server.port=8989

# redis
spring.redis.host=192.168.6.138
spring.redis.port=7000
spring.redis.database=0

使用StringRedisTemplate和RedisTemplate

package com.jin.redis;

import com.jin.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author jinyunlong
 * @date 2021/10/26 11:15
 * @profession ICBC锅炉房保安
 */
//启动springboot应用
@SpringBootTest(classes = SpringBootRedisApplication.class)
@RunWith(SpringRunner.class)
public class TestStringRedisTemplate {

    //注入StringRedisTemplate

    @Autowired
    private StringRedisTemplate stringRedisTemplate; //key value 都是字符串

    //操作redis中key相关
    @Test
    public void testKey(){
        stringRedisTemplate.type("name");    //判断key对应值的类型
        Set<String> keys = stringRedisTemplate.keys("*");//获取redis中所有key
        keys.forEach(key -> System.out.println("key = " + key));
        stringRedisTemplate.delete("name");  //删除一个key
        Boolean name = stringRedisTemplate.hasKey("name");  //判断某个key是否存在
        System.out.println(name);
        Long name1 = stringRedisTemplate.getExpire("name"); //获取key超时时间 -1 永不超时  -2 key不存在 >=0 过期时间
        System.out.println(name1);
        stringRedisTemplate.randomKey();  //在redis中随机获取一个key
//        stringRedisTemplate.rename("age","age1");  //修改key名字 判断key是否存在
        stringRedisTemplate.move("age1",1);
        //etc、、、
    }

    //操作redis中String字符串   opsForValue  实际操作就是redis中String类型
    @Test
    public void testString(){
        stringRedisTemplate.opsForValue().set("name","小豆");  //set 用来设置一个key value
        stringRedisTemplate.opsForValue().set("sqsqs","小grg豆");
        stringRedisTemplate.opsForValue().set("dgd","sasa");
        String value = stringRedisTemplate.opsForValue().get("name");   //用来获取key对应的value
        System.out.println(value);

        stringRedisTemplate.opsForValue().set("code","2357",120, TimeUnit.SECONDS); //设置一个key超时时间
        stringRedisTemplate.opsForValue().append("name","好人");
    }

    //操作redis中List类型    opsForList 实际操作就是redis中list类型
    @Test
    public void testList(){
        stringRedisTemplate.opsForList().leftPush("lll","dsds");  //创建一个列表   并放入一个元素
        stringRedisTemplate.opsForList().leftPushAll("klklkl","Dsdsf","fgfhf","dwetet");  //创建一个列表 放入多个元素
        List<String> objects = new ArrayList<>();
        objects.add("vcvcv");
        objects.add("nbnbnb");
        stringRedisTemplate.opsForList().leftPushAll("objects",objects);   //创建一个
        List<String> range = stringRedisTemplate.opsForList().range("objects",0,-1);  //遍历list
        range.forEach(value -> System.out.println("value = " + value));
    }

    //操作redis中Set类型    opsForSet 实际操作就是redis中set类型
    @Test
    public void testSet(){
        stringRedisTemplate.opsForSet().add("sets","dsds","gfgf","klkl","wewe");  //创建set 并放入多个元素
        Set<String> sets = stringRedisTemplate.opsForSet().members("sets");  //查看set中成员
        sets.forEach(set -> System.out.println("set = " + set));

        Long sets1 = stringRedisTemplate.opsForSet().size("sets");
        System.out.println(sets1);
    }

    //操作redis中Zset类型    opsForZset 实际操作就是redis中zset类型
    @Test
    public void testZSet(){
        stringRedisTemplate.opsForZSet().add("zsets","dsds",200);  //创建并放入元素
        Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);//指定范围查询
        zsets.forEach(value -> System.out.println(value));
    }

    //操作redis中Hash类型    opsForHash 实际操作就是redis中hash类型
    @Test
    public void testHash(){
        stringRedisTemplate.opsForHash().put("maps","name","张三");  //创建一个hash类型 并放入key value

        String o = (String) stringRedisTemplate.opsForHash().get("maps", "name");//获取hash中某个key值

        Map<String,String> map = new HashMap<String,String>();
        map.put("age","12");
        map.put("bir","2012-12-12");
        stringRedisTemplate.opsForHash().putAll("maps",map);  //放入多个key value

        List<Object> objects = stringRedisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age"));
        objects.forEach(object -> System.out.println(object));

        List<Object> maps = stringRedisTemplate.opsForHash().values("maps");//获取所有values

        Set<Object> maps1 = stringRedisTemplate.opsForHash().keys("maps");//获取所有keys

        Long size = stringRedisTemplate.opsForHash().size("maps");
        System.out.println("size = " + size);
    }

    //注入RedisTemplate  key Object Value Object  ===> 对象序列化  name new User() ===> name序列化  对象序列化
    @Autowired
    private RedisTemplate redisTemplate;

    //opsForXXX Value String List Set Zset Hash
    @Test
    public void testRedisTemplate(){

        /**
         * redisTemplate对象中 key 和 value 的序列化都是 JdkSerializationRedisSerializer
         *      key: string
         *      value: object
         *      修改默认key序列化方案  key StringRedisSerializer
         */

        User user = new User();
        //修改key序列化方案  String类型序列(一般常用key是string value是object的模式)
        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        user.setId(UUID.randomUUID().toString()).setName("fsdom").setAge(22).setBir(new Date());
        redisTemplate.opsForValue().set("user",user);   //redis进行设置  对象需要经过序列化
        User user1 = (User) redisTemplate.opsForValue().get("user");
        System.out.println(user1);

        redisTemplate.opsForList().leftPush("list",user);
    }
}

和jedis的api调用大同小异,只不过redisTemplate(StringReidsTemplate)多了一个.opsForXXX(具体要操作的类型)的调用,后面再去跟具体实现的方法。

spring data 为了方便我们对redis进行更友好的操作 因此又提供了bound api 简化操作,这个api的作用是对字符串类型key进行绑定,后续所有操作都是基于这个key操作,绑定list、set等的key有不同的bound方法:

package com.jin.redis;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * @author jinyunlong
 * @date 2021/10/26 16:30
 * @profession ICBC锅炉房保安
 */
@SpringBootTest(classes = SpringBootRedisApplication.class)
@RunWith(SpringRunner.class)
public class TestBoundAPI {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //spring data 为了方便我们对redis进行更友好的操 因此又提供了bound api 简化操作

    @Test
    public void testBound(){
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        //redisTemplate  stringRedisTemplate  将一个key的多次操作进行绑定
        stringRedisTemplate.opsForValue().set("name","zhangsan");
        stringRedisTemplate.opsForValue().append("name","是一个好人");
        String name = stringRedisTemplate.opsForValue().get("name");
        System.out.println(name);

        //对字符串类型key进行绑定,后续所有操作都是基于这个key操作
        BoundValueOperations<String, String> name1 = stringRedisTemplate.boundValueOps("name");
        name1.set("zhangsan");
        name1.append("是一个好人");
        String s = name1.get();
        System.out.println(s);

        //对 list set zset hash
        BoundListOperations<String, String> lists = stringRedisTemplate.boundListOps("lists");
        lists.leftPushAll("zhangsan","lisi","wangwu");
        List<String> range = lists.range(0, -1);
        range.forEach(list -> System.out.println(list));

        //set
//        stringRedisTemplate.boundSetOps();
//        redisTemplate.boundSetOps();
        //zset
//        stringRedisTemplate.boundZSetOps();
//        redisTemplate.boundZSetOps();
        //hash
//        stringRedisTemplate.boundHashOps();
//        stringRedisTemplate.boundHashOps();

        /**
         * 1.针对于日后处理key value 都是String 使用StringRedisTemplate
         * 2.针对于日后处理key value 存在对象 使用RedisTemplate(可以自定义把key(或者value)换成String,
         *   使用redisTemplate.setKeySerializer(new StringRedisSerializer());)
         * 3.针对于同一个key多次操作可以使用boundXXXOps() Value List Set Zset Hash的api简化书写
         */

    }
}

3、Redis的应用场景例
redis应用场景

1.利用redis 中字符串类型完成 项目中手机验证码存储的实现

2.利用redis 中字符串类型完成 具有时效性业务功能 12306 淘宝 订单还有:40分钟

3.利用redis 分布式集群系统中 Session共享 memcache 内存 数据存储上限 数据类型比较简单   redis 内存 数据上限 数据类型单一问题

4.利用redis zset类型 可排序set类型  元素  分数  排行榜之类功能  销量排行 sales(zset) [商品id,商品销量]......

5.利用redis 分布式缓存  实现

6.利用redis 存储认证之后token信息  微信小程序 微信公众号  |用户 openid    --->令牌(token)  redis 超时

7.利用redis 解决分布式集群系统中分布式锁问题   redis 单进程 单线程 n 20 定义
  jvm  1进程开启多个线程 synchronize int n=20
  jvm  1进程开启多个线程 synchronize int n=20
  ...... LUA脚本
etc、其他杂项

redis后面其实还有缓存、主从复制、哨兵机制、集群、分布式session啥的要记,其实要单开一篇来记篇幅可能都不够,但是本人比较懒,这些就都没实践,也不难就简单贴几张概念图吧:

缓存的话一般是给数据持久层做缓存,减轻数据库压力,提升查询效率:

21.PNG

19.png

缓存击穿:说白了就是缓存没被用上。 缓存雪崩:说白了就是缓存挂了。

20.PNG

主从复制:一主多备做备份,但是主如果挂了,剩下的备也不会变成主。引入哨兵机制实现主挂后,备->主。

简单的说哨兵就是带有自动故障转移功能的主从架构

无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限

集群:解决了哨兵的两点问题,其具有高可用可扩展性分布式容错

参考该文章:一文读懂Redis的四种模式,单机、主从、哨兵、集群

分布式session的管理:本质也是一对多的存储关系。

22.png

Redis使用场景的参考文章: Redis读书笔记(一)Redis可以做什么

未来学习计划

Redis的概念、安装、数据操作、与java的集成、应用场景用了三篇文章简单记了一下。马上就要11月份了,再学习下ES,现在日常开发的几个主流中间件就学习复习的差不多了(仅限于会用,实际业务场景来了可能自己都反应不过来这些东西是否应该用)。然后再学学spring5的一些技术点、JVM,最后再实战开发一个某粒商城;可能还不知道要到明年几月份才能学完呢。

道阻且长,继续努力吧😄


标题:Redis(3)
作者:jyl
地址:http://114.116.238.43/articles/2021/10/27/1635302061795.html