淺談RedisTemplate和StringRedisTemplate的區(qū)別
一、區(qū)別
- 區(qū)別點(diǎn)1:兩者的關(guān)系是StringRedisTemplate繼承RedisTemplate。RedisTemplate是一個(gè)泛型類,而StringRedisTemplate則不是。
- 區(qū)別點(diǎn)2:兩者序列化策略不同,
- StringRedisTemplate默認(rèn)采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
- RedisTemplate默認(rèn)采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
- 區(qū)別點(diǎn)3:(疑惑點(diǎn))兩者的數(shù)據(jù)是不共通的;也就是說StringRedisTemplate只能管理StringRedisTemplate里面的數(shù)據(jù),RedisTemplate只能管理RedisTemplate中的數(shù)據(jù)。
- 區(qū)別點(diǎn)4:StringRedisTemplate只能對(duì)key=String,value=String的鍵值對(duì)進(jìn)行操作,RedisTemplate可以對(duì)任何類型的key-value鍵值對(duì)操作。
二、問題總結(jié)
問題1:究竟是數(shù)據(jù)隔離?還是存入的數(shù)據(jù)訪問不到?用詞是否嚴(yán)謹(jǐn)?
答案:嚴(yán)謹(jǐn)說并不是數(shù)據(jù)隔離,而應(yīng)該說成是彼此存入redis的數(shù)據(jù)存在,但是訪問不到;而數(shù)據(jù)隔離通常指的是數(shù)據(jù)存在同一個(gè)庫(kù)下,但是自己只能查看并訪問自己的數(shù)據(jù),而redis中數(shù)據(jù)都能看到且只是使用不同RedisTemplate和StringRedisTemplate對(duì)象彼此訪問不到而已。
問題2:(重要)我自己測(cè)試RedisTemplate和StringRedisTemplate居然都可以彼此訪問到存取的字符串值,為啥?別人文章說數(shù)據(jù)不共通
答案:所謂的彼此訪問不到數(shù)據(jù),前提是自己不重新對(duì)RedisTemplate進(jìn)行序列化設(shè)置,大白話講就是直接使用默認(rèn)的,這樣才能實(shí)現(xiàn)彼此數(shù)據(jù)隔離訪問不到,而實(shí)現(xiàn)了序列化后RedisTemplate和StringRedisTemplate對(duì)字符串類型數(shù)據(jù)就都能獲取了。
而我的能訪問到就是我對(duì)RedisTemplate進(jìn)行了序列化設(shè)置,比如如下代碼,注意這一行: template.setKeySerializer(RedisSerializer.string());這樣設(shè)置后就會(huì)導(dǎo)致RedisTemplate和StringRedisTemplate針對(duì)string類型的屬性值使用了相同的序列化方式,這樣就能彼此訪問到數(shù)據(jù)了;反之不設(shè)置這一行,就會(huì)彼此反問不到數(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使用默認(rèn)序列化方式存值區(qū)別在哪?仍然使用如下代碼,只不過自己不設(shè)置序列化使用默認(rèn)值
@Test public void redisTemplateAndStringRedisTemplate1() { redisTemplate.opsForValue().set("redisTemplateListKey","abc"); stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def"); }
結(jié)果如下:
可以發(fā)現(xiàn)stringRedisTemplate存入的還是字符串樣式,能直接看出屬性值為def,然而RedisTemplate存入的key值前面居然多加了一串16進(jìn)制的字符串值,同時(shí)存入redis的結(jié)果也是轉(zhuǎn)換為字節(jié)數(shù)組bytes之后的看不懂的值。
stringRedisTemplate
RedisTemplate
問題5:.RedisTemplate和StringRedisTemplate存入redis的字符串類型不一致?
答案:區(qū)別在于RedisTemplate存入redis的字符串有雙引號(hào),而StringRedisTemplate存入redis的字符串居然沒有雙引號(hào)。
代碼如下:
@Test public void redisTemplateAndStringRedisTemplate1() { redisTemplate.opsForValue().set("redisTemplateListKey","abc"); stringRedisTemplate.opsForValue().set("stringRedisTemplateListKey","def"); }
結(jié)果展示如下: RedisTemplate
StringRedisTemplate
問題6:兩者的關(guān)系是StringRedisTemplate繼承RedisTemplate。RedisTemplate是一個(gè)泛型類,而StringRedisTemplate則不是。
源碼分析:
先看 StringRedisTemplate:
StringRedisTemplate 是繼承 RedisTemplate的,一般來說子類繼承父類,應(yīng)該能實(shí)現(xiàn)更多的功能,但是此處我們發(fā)現(xiàn) StringRedisTemplate 繼承的是 RedisTemplate的泛型類,指定了String-String的泛型!故功能只專注于String類型!
這下就一目了然了!
再看 RedisTemplate:
問題7:為啥RedisTemplate 需要自定義序列化?
答案:RedisTemplate 可以接收任意的 Object 作為值寫入 Redis,只不過寫入前會(huì)把 Object 序列化為字節(jié)形式,默認(rèn)采用 JDK 序列化。但是這種方式有兩個(gè)缺點(diǎn):
- 可讀性差。對(duì)鍵值對(duì)進(jìn)行了序列化,中文字符串序列化后的內(nèi)容表示為 16 進(jìn)制表示的數(shù)據(jù),
- 可讀性差。內(nèi)存空間占用大。存儲(chǔ)了額外的對(duì)象的類型信息,占用了內(nèi)存空間。
因此,RedisTemplate 需要自定義序列化方式
問題8:對(duì)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的客戶端啟動(dòng),鏈接本地
#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實(shí)體
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(字符串)類型
使用場(chǎng)景:key-value緩存、計(jì)數(shù)
操作對(duì)象:redisTemplate.opsForValue()
添加數(shù)據(jù):set(Object k, Object v);
獲取數(shù)據(jù):get(Object k);
獲取數(shù)據(jù)長(zhǎng)度: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(哈希)類型
使用場(chǎng)景:緩存對(duì)象(string類型也可以實(shí)現(xiàn)-值存json對(duì)象字符串)
操作對(duì)象:redisTemplate.opsForHash()
添加數(shù)據(jù):put(Object h, Object hk, Object hv);
獲取map對(duì)象某值:get(Object h, Object o);
獲取map對(duì)象: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(列表)類型
使用場(chǎng)景:隊(duì)列、棧(左進(jìn)右出:隊(duì)列,左進(jìn)左出:棧)
操作對(duì)象: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 從隊(duì)列左側(cè)取出并刪除數(shù)據(jù) System.err.println(redisTemplate.opsForList().leftPop("list1")); // 通過 list1 從隊(duì)列右側(cè)取出并刪除數(shù)據(jù) System.err.println(redisTemplate.opsForList().rightPop("list1")); }
4、set(無序集合)類型
使用場(chǎng)景:無序且不重復(fù)的集合,求交、差、并集
操作對(duì)象:redisTemplate.opsForSet()
獲取兩個(gè)集合的交集:intersect(Object k, Object k1);
獲取兩個(gè)集合的差集:difference(Object k,Object k1);
獲取兩個(gè)集合的并集: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(有序集合)類型
使用場(chǎng)景:根據(jù)權(quán)重獲取集合
操作對(duì)象: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é):
當(dāng)你的redis數(shù)據(jù)庫(kù)里面本來存的是字符串?dāng)?shù)據(jù)或者你要存取的數(shù)據(jù)就是字符串類型數(shù)據(jù)的時(shí)候,那么你就使用StringRedisTemplate即可,但是如果你的數(shù)據(jù)是復(fù)雜的對(duì)象類型,而取出的時(shí)候又不想做任何的數(shù)據(jù)轉(zhuǎn)換,直接從Redis里面取出一個(gè)對(duì)象,那么使用RedisTemplate是更好的選擇。
到此這篇關(guān)于淺談RedisTemplate和StringRedisTemplate的區(qū)別 的文章就介紹到這了,更多相關(guān)RedisTemplate和StringRedisTemplate的區(qū)別 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Redis教程(二):String數(shù)據(jù)類型
- RedisTemplate常用操作方法總結(jié)(set、hash、list、string等)
- Python操作redis實(shí)例小結(jié)【String、Hash、List、Set等】
- Redis String 類型和 Hash 類型學(xué)習(xí)筆記與總結(jié)
- Redis?存儲(chǔ)對(duì)象信息用?Hash?和String的區(qū)別
- Java三種獲取redis的連接及redis_String類型演示(適合新手)
- Redis中的String類型及使用Redis解決訂單秒殺超賣問題
- Redis基本數(shù)據(jù)類型String常用操作命令
- Redis02 使用Redis數(shù)據(jù)庫(kù)(String類型)全面解析
- 一文搞懂Redis最常用String字符串技能
相關(guān)文章
Redis從單點(diǎn)到集群部署模式(單機(jī)模式?主從模式?哨兵模式)
這篇文章主要為大家介紹了Redis從單點(diǎn)集群部署模式(單機(jī)模式?主從模式?哨兵模式)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11redis實(shí)現(xiàn)session共享的方法
本文主要介紹了redis實(shí)現(xiàn)session共享的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Redis中ziplist壓縮列表的實(shí)現(xiàn)
本文主要介紹了Redis中ziplist壓縮列表的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06詳解redis緩存與數(shù)據(jù)庫(kù)一致性問題解決
這篇文章主要介紹了詳解redis緩存與數(shù)據(jù)庫(kù)一致性問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03