服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - 浅谈RedisTemplate和StringRedisTemplate的区别

浅谈RedisTemplate和StringRedisTemplate的区别

2022-10-21 16:18刘大猫. Redis

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

一、区别

  • 区别点1:两者的关系是StringRedisTemplate继承RedisTemplate。RedisTemplate是一个泛型类,而StringRedisTemplate则不是。
  • 区别点2:两者序列化策略不同,
  • StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
  • RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
  • 区别点3:(疑惑点)两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
  • 区别点4:StringRedisTemplate只能对key=String,value=String的键值对进行操作,RedisTemplate可以对任何类型的key-value键值对操作。

二、问题总结

问题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的序列化

浅谈RedisTemplate和StringRedisTemplate的区别

浅谈RedisTemplate和StringRedisTemplate的区别

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和StringRedisTemplate的区别

RedisTemplate

浅谈RedisTemplate和StringRedisTemplate的区别

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

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

代码如下:

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

结果展示如下: RedisTemplate

浅谈RedisTemplate和StringRedisTemplate的区别

StringRedisTemplate

浅谈RedisTemplate和StringRedisTemplate的区别

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

源码分析:

先看 StringRedisTemplate:

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

浅谈RedisTemplate和StringRedisTemplate的区别

这下就一目了然了!

再看 RedisTemplate:

浅谈RedisTemplate和StringRedisTemplate的区别

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

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

  • 可读性差。对键值对进行了序列化,中文字符串序列化后的内容表示为 16 进制表示的数据,
  • 可读性差。内存空间占用大。存储了额外的对象的类型信息,占用了内存空间。

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

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

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

 

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

  • string(字符串)类型
  • hash(哈希)类型
  • list(列表)类型
  • set(无序集合)类型
  • zset(有序集合)类型

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的区别 内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文地址:https://blog.csdn.net/a924382407/article/details/125165397

延伸 · 阅读

精彩推荐
  • RedisRedis 内存满了怎么办?这样设置才正确!

    Redis 内存满了怎么办?这样设置才正确!

    在 Redis 帝国中,整个帝国的国法、家法和军法等都记录在 redis.conf中,它控制着整个帝国的运行。...

    码哥字节11782022-04-25
  • Redisredis缓存数据库中数据的方法

    redis缓存数据库中数据的方法

    这篇文章主要为大家详细介绍了redis缓存数据库中数据的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    兴奋の大公猴9202022-07-28
  • RedisWindows下redis下载、redis安装及使用教程

    Windows下redis下载、redis安装及使用教程

    redis 提供了多种数据类型来支持不同的业务场景,所以经常使用在分布式锁中,今天给大家讲解redis安装及使用教程,感兴趣的朋友跟随小编一起看看吧...

    weixin_458637864712021-08-09
  • Redis利用Redis实现防止接口重复提交功能

    利用Redis实现防止接口重复提交功能

    大家好,本篇文章主要讲的是利用Redis实现防止接口重复提交功能,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览...

    秃头哥编程11882022-01-24
  • Redis如何用Redis统计海量UV?

    如何用Redis统计海量UV?

    我们先思考一个常见的业务问题:如果你负责开发维护一个大型的网站,有一天老板找产品经理要网站每个网页每天的 UV 数据,然后让你来开发这个统计模...

    程序员小饭7742021-08-10
  • Redisredis的string类型及bitmap介绍

    redis的string类型及bitmap介绍

    这篇文章主要介绍了redis的string类型及bitmap介绍,redis有很多的客户端连接进来,站在redis所在机器的角度来说,就是有很多socket的连接...

    lsd&xql10342022-07-27
  • RedisRedis高并发问题的解决方法

    Redis高并发问题的解决方法

    这篇文章主要介绍了Redis高并发问题的解决办法,具有很好的参考价值,感兴趣的小伙伴们可以参考一下,具体如下: ...

    wow-zyshun6962019-11-13
  • Redis5分钟搭建redis集群(redis5.0.5)

    5分钟搭建redis集群(redis5.0.5)

    本文主要介绍了5分钟搭建redis集群,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    baidu_3855807611262021-09-16