017-学习Redis-SpringDataRedis项目操作类型、设置失效时间、整合哨兵

  • 一、项目搭建
  • 1、创建项目
  • 2、添加配置
  • 3.Lettuce和Jedis的区别
  • 4、测试连接:
  • 5、为什么StringRedisTemplate和RedisTemplate<>都不乱码
  • 二、序列化模板(转JSON数据,并且不乱码)
  • 1、三种方法序列化问题:
  • 2、代码:
  • 1.序列化代码:configuration
  • 2.实体类:一定要imp实现序列化
  • 3.user类型转为字符串,传到redis
  • 4.用redisTemplate测试后:发现不在乱码了,并是json格式:
  • 三、使用StringRedisTemplate手动序列化
  • 如何启动项目:
  • 1、开启redis服务器
  • 2、开启reids的哨兵
  • 3、查看info replication
  • 4、查看日志tail -f /opt/redis/log/sentinel-26381.log
  • 三、操作数据类型
  • 1、String类型
  • 2、hash类型
  • 3、list类型
  • 4、set类型
  • 5、sortedset类型
  • 四、获取所有Key+key失效时间
  • 1、获取所有的key
  • 2、key的失效时间
  • 五、SpringDataRedis整合哨兵
  • 1、第一种方法
  • 2、第二种方法


一、项目搭建

1、创建项目

  1. 选择Spring Initializr
  2. NoSql-redis/ Spring Web
  3. 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>sprintDataRedis-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sprintDataRedis-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring data redis 依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- commons-pool2 对象池依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!--web 依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--test 依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2、添加配置

spring:
 redis:
    # Redis服务器地址
   host: 192.168.0.121
    # Redis服务器端口
   port: 6381
    # Redis服务器端口
   password: root
    # Redis服务器端口
   database: 0
    # 连接超时时间
   timeout: 10000ms
   lettuce:
     pool:
        # 最大连接数,默认8
       max-active: 1024
        # 最大连接阻塞等待时间,单位毫秒,默认-1ms
       max-wait: 10000ms
        # 最大空闲连接,默认8
       max-idle: 200
        # 最小空闲连接,默认0
       min-idle: 5

3.Lettuce和Jedis的区别

Jedis 是一个优秀的基于 Java 语言的 Redis 客户端,但是,其不足也很明显: Jedis 在实现上是直接连接 RedisServer,在多个线程间共享一个 Jedis 实例时是线程不安全的,如果想要在多线程场景下使用 Jedis ,需要使用连接池,每个线程都使用自己的 Jedis 实例,当连接数量增多时,会消耗较多的物理资源。

Lettuce 则完全克服了其线程不安全的缺点: Lettuce 是基于 Netty 的连接(StatefulRedisConnection),Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型。

4、测试连接:

@SpringBootTest
public class SprintDataRedisDemoApplicationTests {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void testRedisTemplate(){
        ValueOperations<String, String> rt = redisTemplate.opsForValue();
        rt.set("rt","testRT");
        String rt1 = rt.get("rt");
        System.out.println(rt1);
    }
    @Test
    public void testStringRedisTemplate() {
        ValueOperations<String, String> srt = stringRedisTemplate.opsForValue();
        //添加一条String类型数据,key=ops,value=test
        srt.set("srt","testSrt");
        String ops1 = srt.get("ops");
        System.out.println(ops1);
    }
}

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_redis

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_02

5、为什么StringRedisTemplate和RedisTemplate<>都不乱码

StringRedisTemplate 继承了 RedisTemplate<String,string>

  • ReidsTemplate 存入后乱码
  • RedisTemplate<>he StringRedisTemplate不乱码
  • springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_序列化_03

  • ReidsTemplate 存入后乱码
  • RedisTemplate<>he StringRedisTemplate不乱码
  • springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_04

    springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_java_05

二、序列化模板(转JSON数据,并且不乱码)

  • 默认情况下的模板 RedisTemplate<Object, Object>,默认序列化使用的是JdkSerializationRedisSerializer ,存储二进制字节码。这时需要自定义模板,当自定义模板后又想存储String 字符串时,可以使StringRedisTemplate的方式,他们俩并不冲突。

1、三种方法序列化问题:

  • 自定义模板解决序列化问题

序列化问题:
要把 domain object 做为 key-value 对保存在 redis 中,就必须要解决对象的序列化问题。Spring Data Redis给我们
提供了一些现成的方案:

  • JdkSerializationRedisSerializer 使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗 Redis 服务器的大量内存。
  • Jackson2JsonRedisSerializer 使用 Jackson 库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串
    短小精悍。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。通过查看源代码,发现其只在反序列化过程中用到了类型信息。
  • GenericJackson2JsonRedisSerializer 通用型序列化,这种序列化方式不用自己手动指定对象的 Class

2、代码:

1.序列化代码:configuration

Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory
redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        //为string类型key设置序列器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //为string类型value设置序列器
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        //为hash类型key设置序列器
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //为hash类型value设置序列器
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
   }
}

序列化方式二:

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_序列化_06

2.实体类:一定要imp实现序列化

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_数据库_07

3.user类型转为字符串,传到redis

Test:

/**
* 测试序列化
* 将user类型,转为字符串传到redis
*/
@Autowired
private RedisTemplate  redisTemplate;

@Test
public void testSerial(){
    User user = new User();
    user.setId(1);
    user.setUsername("张三");
    user.setPassword("111");
    ValueOperations<String, Object> value = redisTemplate.opsForValue();
    value.set("userInfo",user);
    System.out.println(value.get("userInfo"));
}

4.用redisTemplate测试后:发现不在乱码了,并是json格式:

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_java_08

三、使用StringRedisTemplate手动序列化

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_09

如何启动项目:

1、开启redis服务器

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_java_10

2、开启reids的哨兵

./redis-sentinel /opt/redis/conf/sentinel-26379.conf

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_11

3、查看info replication

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_序列化_12

4、查看日志tail -f /opt/redis/log/sentinel-26381.log

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_java_13

三、操作数据类型

1、String类型

//测试String类型
    @Test
    public void testString(){
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("setTest","test");
        //读取数据
        String name = (String) valueOperations.get("setTest");
        System.out.println(name);

        //添加层级目录:
        valueOperations.set("user:01","lisi");
        //添加多条数据
        Map<String,String> hashMap = new HashMap();
        hashMap.put("map01","value01");
        hashMap.put("map02","value02");
        valueOperations.multiSet(hashMap);
        //获取多条数据\
        List<String> keys= new ArrayList<>();
        keys.add("setTest");
        keys.add("map01");
        keys.add("map02");
        List list = valueOperations.multiGet(keys);
        list.forEach(System.out::println);
        //通用的删除方法
        redisTemplate.delete("map01");
    }

2、hash类型

//测试hash类型
    @Test
    public void testHash(){
        HashOperations hashOperations = redisTemplate.opsForHash();
        /**
         * 添加一条数据,
         * 第一个参数是 Redis的key
         * 第二个参数是 hash的key
         * 第三个参数是 hash的value
         */
        hashOperations.put("users","name","zhangsanHash");
        //添加多条数据
        Map<String,String> map = new HashMap<>();
        map.put("age","12");
        map.put("address","beijing");
        hashOperations.putAll("users",map);
        //获取多条数据
        List<String> list = new ArrayList<>();
        list.add("name");
        list.add("age");
        list.add("address");
        //通过key,来获取对应的value
        List users = hashOperations.multiGet("users", list);
        users.forEach(System.out::println);
        //获取map的所有的数据类型
        Map<String,String> entries = hashOperations.entries("users");
        entries.entrySet().forEach(e->{
            System.out.println(e.getKey()+"---->"+e.getValue());
        });
    }

3、list类型

// 3.操作list
@Test
public void testList() {
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
// 左添加(上)
//       listOperations.leftPush("students", "Wang Wu");
//       listOperations.leftPush("students", "Li Si");
// 左添加(上) 把value值放到key对应列表中pivot值的左面,如果pivot值存在的话
//listOperations.leftPush("students", "Wang Wu", "Li Si");
// 右添加(下)
//       listOperations.rightPush("students", "Zhao Liu");
// 获取 start起始下标 end结束下标 包含关系
List<Object> students = listOperations.range("students", 0,2);
for (Object stu : students) {
System.out.println(stu);
}
// 根据下标获取
Object stu = listOperations.index("students", 1);
System.out.println(stu);
// 获取总条数
Long total = listOperations.size("students");
System.out.println("总条数:" + total);
// 删除单条 删除列表中存储的列表中几个出现的Li Si。
listOperations.remove("students", 1, "Li Si");
// 删除多条
redisTemplate.delete("students");
}

4、set类型

// 4.操作set-无序
@Test
public void testSet() {
    SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
    // 添加数据
    String[] letters = new String[]{"aaa", "bbb", "ccc", "ddd", "eee"};
    //setOperations.add("letters", "aaa", "bbb", "ccc", "ddd", "eee");
    setOperations.add("letters", letters);
    // 获取数据
    Set<Object> let = setOperations.members("letters");
    for (Object letter: let) {
        System.out.println(letter);
   }
    // 删除
    setOperations.remove("letters", "aaa", "bbb");
}

5、sortedset类型

// 5.操作sorted set-有序
@Test
public void testSortedSet() {
    ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
    ZSetOperations.TypedTuple<Object> objectTypedTuple1 =
            new DefaultTypedTuple<Object>("zhangsan", 7D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple2 =
            new DefaultTypedTuple<Object>("lisi", 3D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple3 =
            new DefaultTypedTuple<Object>("wangwu", 5D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple4 =
            new DefaultTypedTuple<Object>("zhaoliu", 6D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple5 =
            new DefaultTypedTuple<Object>("tianqi", 2D);
    Set<ZSetOperations.TypedTuple<Object>> tuples = new
HashSet<ZSetOperations.TypedTuple<Object>>();
    tuples.add(objectTypedTuple1);
    tuples.add(objectTypedTuple2);
    tuples.add(objectTypedTuple3);
    tuples.add(objectTypedTuple4);
    tuples.add(objectTypedTuple5);
    // 添加数据
    zSetOperations.add("score", tuples);
    // 获取数据
    Set<Object> scores = zSetOperations.range("score", 0, 4);
    for (Object score: scores) {
        System.out.println(score);
   }
    // 获取总条数
    Long total = zSetOperations.size("score");
    System.out.println("总条数:" + total);
    // 删除
    zSetOperations.remove("score", "zhangsan", "lisi");
}

四、获取所有Key+key失效时间

1、获取所有的key

// 测试获取有的key的数量
    @Test
    public void testKey(){
        Set keys = redisTemplate.keys("*");
        keys.forEach(System.out::println);
    }

2、key的失效时间

//测试失效时间:
    @Test
    public void testExpire(){
        //第一种设置失效时间
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //valueOperations.set("testCode","test",20, TimeUnit.SECONDS);

        //第二种, 给以及存在的key设置失效的时间:
        redisTemplate.expire("users",20, TimeUnit.SECONDS);

        /*//查看失效的时间
        Long testCode = redisTemplate.getExpire("testCode");
        System.out.println(testCode);*/
    }

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_14


springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_Redis_15

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_数据库_16

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_序列化_17

五、SpringDataRedis整合哨兵

上个文章搭建了主从服用、主备切换,用哨兵去监控master节点。那么SpringDateRedis也可以整合哨兵。letts才支持。

1、第一种方法

springboot 配置redisson 哨兵 springboot redis 哨兵 过期消息_数据库_18

#哨兵模式
 sentinel:
   #主节点名称
   master: mymaster
   #节点
   nodes:  192.168.0.121:26379,192.168.0.121:26380,192.168.0.121:26381

2、第二种方法

conf/RedisConfig

//加入哨兵bean
@Bean
public RedisSentinelConfiguration redisSentinelConfiguration(){
    RedisSentinelConfiguration rsc = new RedisSentinelConfiguration()
            .master("mymaster")
            .sentinel("192.168.0.121",26379)
            .sentinel("192.168.0.121",26380)
            .sentinel("192.168.0.121",26381);
    //设置登录密码
    rsc.setPassword("root");
    return rsc;
}