欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot混合使用StringRedisTemplate和RedisTemplate的坑及解決

 更新時間:2023年12月20日 16:01:18   作者:程序新視界  
這篇文章主要介紹了SpringBoot混合使用StringRedisTemplate和RedisTemplate的坑及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

但在實踐中,有朋友遇到這樣的問題,就是存儲到Redis數(shù)據(jù)取不到值。

兩種Template的源碼分析

這是為什么呢?是因為他同時使用了StringRedisTemplate和RedisTemplate在Redis中存儲和讀取數(shù)據(jù)。

它們最重要的一個區(qū)別就是默認采用的序列化方式不同(在課程中已經(jīng)講到)。

這里我們再來回顧一下相關(guān)源碼,StringRedisTemplate的部分源碼如下:

public class StringRedisTemplate extends RedisTemplate<String, String> {

	/**
	 * Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
	 * and {@link #afterPropertiesSet()} still need to be called.
	 */
	public StringRedisTemplate() {
		setKeySerializer(RedisSerializer.string());
		setValueSerializer(RedisSerializer.string());
		setHashKeySerializer(RedisSerializer.string());
		setHashValueSerializer(RedisSerializer.string());
	}
    
}

通過該源碼我們可以看到StringRedisTemplate采用的是RedisSerializer.string()來序列化Redis中存儲數(shù)據(jù)的Key的。

下面再來看看RedisTemplate中默認采用什么形式來序列化對應的Key。

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
    // 省略其他源碼
	private @Nullable RedisSerializer<?> defaultSerializer;
	private @Nullable ClassLoader classLoader;

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisAccessor#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() {

		super.afterPropertiesSet();

		boolean defaultUsed = false;

		if (defaultSerializer == null) {

			defaultSerializer = new JdkSerializationRedisSerializer(
					classLoader != null ? classLoader : this.getClass().getClassLoader());
		}

		if (enableDefaultSerializer) {

			if (keySerializer == null) {
				keySerializer = defaultSerializer;
				defaultUsed = true;
			}
			// 省略其他源碼
		}

		if (enableDefaultSerializer && defaultUsed) {
			Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
		}

		if (scriptExecutor == null) {
			this.scriptExecutor = new DefaultScriptExecutor<>(this);
		}

		initialized = true;
	}
	// 省略其他源碼
    
}

我們可以看到RedisTemplate使用的序列化類為defaultSerializer,默認情況下為JdkSerializationRedisSerializer。

如果未指定Key的序列化類,keySerializer與defaultSerializer采用相同的序列化類。

通過上述兩個Template的分析我們就可以看出它們在Redis存儲的Key,采用了不同的序列化方法。

而且JdkSerializationRedisSerializer序列化時會在Key的前面添加一些特殊字符。

還原測試

下面先看一個單元測試:

@Slf4j
@SpringBootTest
class RedisDifferentTemplateTest {
	@Resource
	private RedisTemplate<String, Object> redisTemplate;

	@Resource
	private StringRedisTemplate stringRedisTemplate;

	@Test
	void testSimple() {
		redisTemplate.opsForValue().set("myWeb", "www.choupangxia.com");
		Assertions.assertEquals("www.choupangxia.com", redisTemplate.opsForValue().get("myWeb"));

		Assertions.assertEquals("www.choupangxia.com",stringRedisTemplate.opsForValue().get("myWeb"));
	}
}

在上述方法中先通過redisTemplate存儲一個key為myWeb的數(shù)據(jù)到Redis中,隨后通過redisTemplate獲取并判斷斷言,可以成功通過。

但隨后通過stringRedisTemplate獲取同樣的key的值,則拋出異常,異常信息如下:

org.opentest4j.AssertionFailedError: 

Expected :www.choupangxia.com

Actual   :null

 <Click to see difference>

也就是說獲取的結(jié)果為null。

那么,我們再通過Redis客戶端看一下兩種形式存儲到redis中key的值的情況。

image

我們可以看到通過StringRedisTemplate存儲的數(shù)據(jù)Key為“myWeb”,而RedisTemplate存儲的Key為“\xAC\xED\x00\x05t\x00\x05myWeb”,這也就是為什么默認情況下兩者存儲的數(shù)據(jù)沒辦法混合使用了。

解決方案

那么,如果在生產(chǎn)環(huán)境中想通用StringRedisTemplate和RedisTemplate進行字符串的處理該怎么辦?

此時就需要指定統(tǒng)一的Key的序列化處理類,比如在RedisTemplate序列化時指定與StringRedisTemplate相同的類。

在上述單元測試中添加如下方法:

@BeforeEach
void init() {
	redisTemplate.setKeySerializer(RedisSerializer.string());
}

也就是設(shè)置RedisTemplate也使用RedisSerializer.string()來序列化Key。注意此處使用的是Junit5。

這樣就解決問題了嗎?沒有。因為RedisTemplate的Value也是采用默認的序列化類,也要進行統(tǒng)一修改。

因此上面的方法變成如下:

@BeforeEach
void init() {
	redisTemplate.setKeySerializer(RedisSerializer.string());
	redisTemplate.setValueSerializer(RedisSerializer.string());
}

總結(jié)

經(jīng)過上述步驟,關(guān)于SpringBoot中混合使用StringRedisTemplate和RedisTemplate的坑已經(jīng)填平了。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。 

相關(guān)文章

  • Java線程池高頻面試題總結(jié)

    Java線程池高頻面試題總結(jié)

    在進程和線程的相關(guān)面試題中還有一部分是關(guān)于多線程和線程池的,也是在這一部分中比較常考察的內(nèi)容。本篇文章就帶你了解一下,希望能給你帶來幫助
    2021-08-08
  • 一文搞懂MyBatis一級緩存和二級緩存

    一文搞懂MyBatis一級緩存和二級緩存

    本文主要介紹了一文搞懂MyBatis一級緩存和二級緩存,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • JDK安裝配置教程

    JDK安裝配置教程

    這篇文章主要為大家詳細介紹了JDK安裝配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 詳解Java 10 var關(guān)鍵字和示例教程

    詳解Java 10 var關(guān)鍵字和示例教程

    在本文中,我將通過示例介紹新的Java SE 10特性——“var”類型。你將學習如何在代碼中正確使用它,以及在什么情況下不能使用它,需要的朋友可以參考下
    2018-10-10
  • mybatis?foreach?list特殊處理方式

    mybatis?foreach?list特殊處理方式

    這篇文章主要介紹了mybatis?foreach?list特殊處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • javaSE基礎(chǔ)如何通俗的理解javaBean是什么

    javaSE基礎(chǔ)如何通俗的理解javaBean是什么

    所謂的Java Bean,就是一個java類,編譯后成為了一個后綴名是 .class的文件。這就是Java Bean,很多初學者,包括當年的我自己,總是被這些專有名詞搞的暈頭轉(zhuǎn)向
    2021-10-10
  • IDEA中設(shè)置Tab健為4個空格的方法

    IDEA中設(shè)置Tab健為4個空格的方法

    這篇文章給大家介紹了代碼縮進用空格還是Tab?(IDEA中設(shè)置Tab健為4個空格)的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-03-03
  • Java實現(xiàn)統(tǒng)計文檔中關(guān)鍵字出現(xiàn)的次數(shù)

    Java實現(xiàn)統(tǒng)計文檔中關(guān)鍵字出現(xiàn)的次數(shù)

    這篇文章主要為大家分享了利用Java語言實現(xiàn)統(tǒng)計關(guān)鍵字在文檔中出現(xiàn)的次數(shù)的方法,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-05-05
  • JAVA代碼開發(fā)規(guī)范

    JAVA代碼開發(fā)規(guī)范

    本文主要對JAVA代碼開發(fā)規(guī)范進行詳細介紹,具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • Spring?Boot?接口加解密功能實現(xiàn)

    Spring?Boot?接口加解密功能實現(xiàn)

    在我們?nèi)粘5腏ava開發(fā)中,免不了和其他系統(tǒng)的業(yè)務交互,或者微服務之間的接口調(diào)用;如果我們想保證數(shù)據(jù)傳輸?shù)陌踩?,對接口出參加密,入?yún)⒔饷?,這篇文章主要介紹了Spring?Boot?接口加解密功能實現(xiàn),需要的朋友可以參考下
    2023-04-04

最新評論