Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > RedisTemplate和StringRedisTemplate的区别

浅谈RedisTemplate和StringRedisTemplate的区别

作者:刘大猫.

本文主要介绍了RedisTemplate和StringRedisTemplate的区别及个人见解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一、区别

二、问题总结

问题1:究竟是数据隔离?还是存入的数据访问不到?用词是否严谨?

答案:严谨说并不是数据隔离,而应该说成是彼此存入redis的数据存在,但是访问不到;而数据隔离通常指的是数据存在同一个库下,但是自己只能查看并访问自己的数据,而redis中数据都能看到且只是使用不同RedisTemplate和StringRedisTemplate对象彼此访问不到而已。

问题2:(重要)我自己测试RedisTemplate和StringRedisTemplate居然都可以彼此访问到存取的字符串值,为啥?别人文章说数据不共通

答案:所谓的彼此访问不到数据,前提是自己不重新对RedisTemplate进行序列化设置,大白话讲就是直接使用默认的,这样才能实现彼此数据隔离访问不到,而实现了序列化后RedisTemplate和StringRedisTemplate对字符串类型数据就都能获取了。

而我的能访问到就是我对RedisTemplate进行了序列化设置,比如如下代码,注意这一行: template.setKeySerializer(RedisSerializer.string());这样设置后就会导致RedisTemplate和StringRedisTemplate针对string类型的属性值使用了相同的序列化方式,这样就能彼此访问到数据了;反之不设置这一行,就会彼此反问不到数据。

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig  {
   
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //key的序列化采用String类型的
        template.setKeySerializer(RedisSerializer.string());
        //value的序列化采用jackson类型
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        //hash的key的序列化也采用String类型
        template.setHashKeySerializer(RedisSerializer.string());
        //value的序列化采用jackson类型
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

问题3:.源码分析RedisTemplate和StringRedisTemplate的序列化方式

RedisTemplate的序列化

StringRedisTemplate的序列化

问题4:.RedisTemplate和StringRedisTemplate使用默认序列化方式存值区别在哪?仍然使用如下代码,只不过自己不设置序列化使用默认值

@Test
public void redisTemplateAndStringRedisTemplate1() {
    redisTemplate.opsForValue().set("redisTemplateListKey","abc");
    stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def");
}

结果如下:

可以发现stringRedisTemplate存入的还是字符串样式,能直接看出属性值为def,然而RedisTemplate存入的key值前面居然多加了一串16进制的字符串值,同时存入redis的结果也是转换为字节数组bytes之后的看不懂的值。

stringRedisTemplate

RedisTemplate

问题5:.RedisTemplate和StringRedisTemplate存入redis的字符串类型不一致?

答案:区别在于RedisTemplate存入redis的字符串有双引号,而StringRedisTemplate存入redis的字符串居然没有双引号。

代码如下:

@Test
public void redisTemplateAndStringRedisTemplate1() {
    redisTemplate.opsForValue().set("redisTemplateListKey","abc");
    stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def");
}

结果展示如下: RedisTemplate

StringRedisTemplate

问题6:两者的关系是StringRedisTemplate继承RedisTemplate。RedisTemplate是一个泛型类,而StringRedisTemplate则不是。

源码分析:

先看 StringRedisTemplate:

StringRedisTemplate 是继承 RedisTemplate的,一般来说子类继承父类,应该能实现更多的功能,但是此处我们发现 StringRedisTemplate 继承的是 RedisTemplate的泛型类,指定了String-String的泛型!故功能只专注于String类型!

这下就一目了然了!

再看 RedisTemplate:

问题7:为啥RedisTemplate 需要自定义序列化?

答案:RedisTemplate 可以接收任意的 Object 作为值写入 Redis,只不过写入前会把 Object 序列化为字节形式,默认采用 JDK 序列化。但是这种方式有两个缺点:

因此,RedisTemplate 需要自定义序列化方式

问题8:对redis的value使用序列化方式有几种?

答案:4种:字符串序列化、json序列化、jdk序列化
JdkSerializationRedisSerializer、StringRedisSerializer、GenericJackson2JsonRedisSerializer、GenericFastJsonRedisSerializer。
其中:StringRedisSerializer =》 字符串序列化
JdkSerializationRedisSerializer =》 jdk序列化
GenericJackson2JsonRedisSerializer和GenericFastJsonRedisSerializer =》 json序列化

三、案例:springboot整合redis五种数据结构API

pom依赖

<!--redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>
<!--redis锁-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.13.6</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.10.1</version>
</dependency>

环境变量配置,redis采用windows的客户端启动,链接本地

#redis
spring.redis.database=15
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.pool.max-active=200
spring.redis.jedis.pool.max-wait= -1
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout = 10000

User实体

package com.example.demo.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //姓名
    private String name;
    //密码
    private String password;
}

1、string(字符串)类型

使用场景:key-value缓存、计数
操作对象:redisTemplate.opsForValue()
添加数据:set(Object k, Object v);
获取数据:get(Object k);
获取数据长度:size(Object k);
拼接内容:append(Object k, String s);
数值加一:increment(Object k);
数值减一:decrement(Object k);

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.DemoApplication;
import com.example.demo.bean.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.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisControllerTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

	//string类型添加
    @Test
    public void stringAdd() {
        // 添加redis 字符类型数据 strKey1
        redisTemplate.opsForValue().set("strKey1","一段话。。。");

        // 添加redis 字符类型数据 strKey2
        JSONObject json = new JSONObject();
        json.put("dog","狗");
        json.put("cat","猫");
        redisTemplate.opsForValue().set("strKey2",json.toJSONString());
    }
    //string类型查询
    @Test
    public void stringQuery() {
        // 通过 strKey1 获取并打印值
        System.err.println(redisTemplate.opsForValue().get("strKey1"));
        // 通过 strKey2 获取并打印值
        System.err.println(redisTemplate.opsForValue().get("strKey2"));
    }

2、hash(哈希)类型

使用场景:缓存对象(string类型也可以实现-值存json对象字符串)
操作对象:redisTemplate.opsForHash()
添加数据:put(Object h, Object hk, Object hv);
获取map对象某值:get(Object h, Object o);
获取map对象:entries(Object h);

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.DemoApplication;
import com.example.demo.bean.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.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisControllerTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

	//hash类型添加
    @Test
    public void hashAdd() {
        // 添加数据
        redisTemplate.opsForHash().put("hash1","key1","value1");
        redisTemplate.opsForHash().put("hash1","key2","value2");
    }
    //hash类型查询
    @Test
    public void hashQuery() {
        // 通过 h1 获取值
        System.err.println(redisTemplate.opsForHash().get("hash1","key1"));
        System.err.println(redisTemplate.opsForHash().entries("hash1"));
    }

3、list(列表)类型

使用场景:队列、栈(左进右出:队列,左进左出:栈)
操作对象:redisTemplate.opsForList()
从列表左侧添加数据:leftPush(Object k, Object v);
从列表左侧取数据:leftPop(Object k);
从列表右侧取数据:rightPop(Object k);

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.DemoApplication;
import com.example.demo.bean.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.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisControllerTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

	//list类型添加
    @Test
    public void listAdd() {
        List list = new ArrayList<>();
        User user1 = new User("老赵", "123");
        User user2 = new User("老曹", "456");
        list.add(user1);
        list.add(user2);
        // 直接添加list
        redisTemplate.opsForList().leftPush("listKey",list);

        //循环添加元素
        redisTemplate.opsForList().leftPush("list1","v1");
        redisTemplate.opsForList().leftPush("list1","v2");
        redisTemplate.opsForList().leftPush("list1","v3");
    }
    //list类型查询
    @Test
    public void listQuery() {
        System.err.println(redisTemplate.opsForList().leftPop("listKey"));
        // 通过 list1 从队列左侧取出并删除数据
        System.err.println(redisTemplate.opsForList().leftPop("list1"));
        // 通过 list1 从队列右侧取出并删除数据
        System.err.println(redisTemplate.opsForList().rightPop("list1"));
    }

4、set(无序集合)类型

使用场景:无序且不重复的集合,求交、差、并集
操作对象:redisTemplate.opsForSet()
获取两个集合的交集:intersect(Object k, Object k1);
获取两个集合的差集:difference(Object k,Object k1);
获取两个集合的并集:union(Object k,Object k1);

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.DemoApplication;
import com.example.demo.bean.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.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisControllerTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

	//set(无序集合)类型添加
    @Test
    public void setAdd() {
        User user1 = new User("老赵", "123");
        User user2 = new User("老曹", "456");
        // 添加数据
        redisTemplate.opsForSet().add("set1","v1","v2","v3");
        redisTemplate.opsForSet().add("set2","v1");
        redisTemplate.opsForSet().add("set3",user1, user2);
    }
    //set(无序集合)类型查询
    @Test
    public void setQuery() {
        // 求交集
        System.err.println(redisTemplate.opsForSet().intersect("set1","set2"));
        // 求差集
        System.err.println(redisTemplate.opsForSet().difference("set1","set2"));
        // 求并集
        System.err.println(redisTemplate.opsForSet().union("set1","set2"));
        System.err.println(redisTemplate.opsForSet().members("set3"));
    }

5、zset(有序集合)类型

使用场景:根据权重获取集合
操作对象:redisTemplate.opsForZSet()
添加数据:add(Object k, Object v, Object v1);
根据权重范围获取集合:rangeByScore(Object k,Object v,Object v1);

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.DemoApplication;
import com.example.demo.bean.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.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisControllerTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

	//zset(有序集合)类型添加
    @Test
    public void zsetAdd() {
        // 添加数据
        redisTemplate.opsForZSet().add("zset1","A",1);
        redisTemplate.opsForZSet().add("zset1","B",3);
        redisTemplate.opsForZSet().add("zset1","C",2);
        redisTemplate.opsForZSet().add("zset1","D",5);
    }
    //zset(有序集合)类型查询
    @Test
    public void zsetQuery() {
        System.err.println(redisTemplate.opsForZSet().rangeByScore("zset1",1,4));
    }

6、删除key

//删除key
@Test
public void deleteKey() {
    //删除key
    redisTemplate.delete("strKey1");
}

四、总结:

当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。

 到此这篇关于浅谈RedisTemplate和StringRedisTemplate的区别 的文章就介绍到这了,更多相关RedisTemplate和StringRedisTemplate的区别 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文