淺談RedisTemplate和StringRedisTemplate的區(qū)別
一、區(qū)別
- 區(qū)別點1:兩者的關系是StringRedisTemplate繼承RedisTemplate。RedisTemplate是一個泛型類,而StringRedisTemplate則不是。
- 區(qū)別點2:兩者序列化策略不同,
- StringRedisTemplate默認采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
- RedisTemplate默認采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
- 區(qū)別點3:(疑惑點)兩者的數(shù)據(jù)是不共通的;也就是說StringRedisTemplate只能管理StringRedisTemplate里面的數(shù)據(jù),RedisTemplate只能管理RedisTemplate中的數(shù)據(jù)。
- 區(qū)別點4:StringRedisTemplate只能對key=String,value=String的鍵值對進行操作,RedisTemplate可以對任何類型的key-value鍵值對操作。
二、問題總結(jié)
問題1:究竟是數(shù)據(jù)隔離?還是存入的數(shù)據(jù)訪問不到?用詞是否嚴謹?
答案:嚴謹說并不是數(shù)據(jù)隔離,而應該說成是彼此存入redis的數(shù)據(jù)存在,但是訪問不到;而數(shù)據(jù)隔離通常指的是數(shù)據(jù)存在同一個庫下,但是自己只能查看并訪問自己的數(shù)據(jù),而redis中數(shù)據(jù)都能看到且只是使用不同RedisTemplate和StringRedisTemplate對象彼此訪問不到而已。
問題2:(重要)我自己測試RedisTemplate和StringRedisTemplate居然都可以彼此訪問到存取的字符串值,為啥?別人文章說數(shù)據(jù)不共通
答案:所謂的彼此訪問不到數(shù)據(jù),前提是自己不重新對RedisTemplate進行序列化設置,大白話講就是直接使用默認的,這樣才能實現(xiàn)彼此數(shù)據(jù)隔離訪問不到,而實現(xiàn)了序列化后RedisTemplate和StringRedisTemplate對字符串類型數(shù)據(jù)就都能獲取了。
而我的能訪問到就是我對RedisTemplate進行了序列化設置,比如如下代碼,注意這一行: template.setKeySerializer(RedisSerializer.string());這樣設置后就會導致RedisTemplate和StringRedisTemplate針對string類型的屬性值使用了相同的序列化方式,這樣就能彼此訪問到數(shù)據(jù)了;反之不設置這一行,就會彼此反問不到數(shù)據(jù)。
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使用默認序列化方式存值區(qū)別在哪?仍然使用如下代碼,只不過自己不設置序列化使用默認值
@Test
public void redisTemplateAndStringRedisTemplate1() {
redisTemplate.opsForValue().set("redisTemplateListKey","abc");
stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def");
}
結(jié)果如下:
可以發(fā)現(xiàn)stringRedisTemplate存入的還是字符串樣式,能直接看出屬性值為def,然而RedisTemplate存入的key值前面居然多加了一串16進制的字符串值,同時存入redis的結(jié)果也是轉(zhuǎn)換為字節(jié)數(shù)組bytes之后的看不懂的值。
stringRedisTemplate

RedisTemplate

問題5:.RedisTemplate和StringRedisTemplate存入redis的字符串類型不一致?
答案:區(qū)別在于RedisTemplate存入redis的字符串有雙引號,而StringRedisTemplate存入redis的字符串居然沒有雙引號。
代碼如下:
@Test
public void redisTemplateAndStringRedisTemplate1() {
redisTemplate.opsForValue().set("redisTemplateListKey","abc");
stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def");
}
結(jié)果展示如下: RedisTemplate

StringRedisTemplate

問題6:兩者的關系是StringRedisTemplate繼承RedisTemplate。RedisTemplate是一個泛型類,而StringRedisTemplate則不是。
源碼分析:
先看 StringRedisTemplate:
StringRedisTemplate 是繼承 RedisTemplate的,一般來說子類繼承父類,應該能實現(xiàn)更多的功能,但是此處我們發(fā)現(xiàn) StringRedisTemplate 繼承的是 RedisTemplate的泛型類,指定了String-String的泛型!故功能只專注于String類型!

這下就一目了然了!
再看 RedisTemplate:

問題7:為啥RedisTemplate 需要自定義序列化?
答案:RedisTemplate 可以接收任意的 Object 作為值寫入 Redis,只不過寫入前會把 Object 序列化為字節(jié)形式,默認采用 JDK 序列化。但是這種方式有兩個缺點:
- 可讀性差。對鍵值對進行了序列化,中文字符串序列化后的內(nèi)容表示為 16 進制表示的數(shù)據(jù),
- 可讀性差。內(nèi)存空間占用大。存儲了額外的對象的類型信息,占用了內(nèi)存空間。
因此,RedisTemplate 需要自定義序列化方式
問題8:對redis的value使用序列化方式有幾種?
答案:4種:字符串序列化、json序列化、jdk序列化
JdkSerializationRedisSerializer、StringRedisSerializer、GenericJackson2JsonRedisSerializer、GenericFastJsonRedisSerializer。
其中:StringRedisSerializer =》 字符串序列化
JdkSerializationRedisSerializer =》 jdk序列化
GenericJackson2JsonRedisSerializer和GenericFastJsonRedisSerializer =》 json序列化
三、案例:springboot整合redis五種數(shù)據(jù)結(jié)構(gòu)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>
環(huán)境變量配置,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緩存、計數(shù)
操作對象:redisTemplate.opsForValue()
添加數(shù)據(jù):set(Object k, Object v);
獲取數(shù)據(jù):get(Object k);
獲取數(shù)據(jù)長度:size(Object k);
拼接內(nèi)容:append(Object k, String s);
數(shù)值加一:increment(Object k);
數(shù)值減一: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 字符類型數(shù)據(jù) strKey1
redisTemplate.opsForValue().set("strKey1","一段話。。。");
// 添加redis 字符類型數(shù)據(jù) 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類型也可以實現(xiàn)-值存json對象字符串)
操作對象:redisTemplate.opsForHash()
添加數(shù)據(jù):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() {
// 添加數(shù)據(jù)
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()
從列表左側(cè)添加數(shù)據(jù):leftPush(Object k, Object v);
從列表左側(cè)取數(shù)據(jù):leftPop(Object k);
從列表右側(cè)取數(shù)據(jù):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);
//循環(huán)添加元素
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 從隊列左側(cè)取出并刪除數(shù)據(jù)
System.err.println(redisTemplate.opsForList().leftPop("list1"));
// 通過 list1 從隊列右側(cè)取出并刪除數(shù)據(jù)
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");
// 添加數(shù)據(jù)
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(有序集合)類型
使用場景:根據(jù)權(quán)重獲取集合
操作對象:redisTemplate.opsForZSet()
添加數(shù)據(jù):add(Object k, Object v, Object v1);
根據(jù)權(quán)重范圍獲取集合: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() {
// 添加數(shù)據(jù)
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");
}
四、總結(jié):
當你的redis數(shù)據(jù)庫里面本來存的是字符串數(shù)據(jù)或者你要存取的數(shù)據(jù)就是字符串類型數(shù)據(jù)的時候,那么你就使用StringRedisTemplate即可,但是如果你的數(shù)據(jù)是復雜的對象類型,而取出的時候又不想做任何的數(shù)據(jù)轉(zhuǎn)換,直接從Redis里面取出一個對象,那么使用RedisTemplate是更好的選擇。
到此這篇關于淺談RedisTemplate和StringRedisTemplate的區(qū)別 的文章就介紹到這了,更多相關RedisTemplate和StringRedisTemplate的區(qū)別 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Redis教程(二):String數(shù)據(jù)類型
- RedisTemplate常用操作方法總結(jié)(set、hash、list、string等)
- Python操作redis實例小結(jié)【String、Hash、List、Set等】
- Redis String 類型和 Hash 類型學習筆記與總結(jié)
- Redis?存儲對象信息用?Hash?和String的區(qū)別
- Java三種獲取redis的連接及redis_String類型演示(適合新手)
- Redis中的String類型及使用Redis解決訂單秒殺超賣問題
- Redis基本數(shù)據(jù)類型String常用操作命令
- Redis02 使用Redis數(shù)據(jù)庫(String類型)全面解析
- 一文搞懂Redis最常用String字符串技能
相關文章
Redis中統(tǒng)計各種數(shù)據(jù)大小的方法
這篇文章主要介紹了Redis中統(tǒng)計各種數(shù)據(jù)大小的方法,本文使用PHP實現(xiàn)統(tǒng)計Redis內(nèi)存占用比較大的鍵,需要的朋友可以參考下2015-03-03

