1. 程式人生 > 其它 >hash redis springboot_Redis | SpringBoot整合Redis

hash redis springboot_Redis | SpringBoot整合Redis

技術標籤:hash redis springboot

Redis 的常用命令在其他的文章中都已經介紹完了。作為程式設計師不是要在命令列中使用 Redis,畢竟我們要把 Redis 當做快取、佇列等進行使用時,因此重點還是要在程式碼中使用。那麼,我們就需要去掌握 Redis 相關的 API 的使用方法。

Spring Boot 整合 Redis

目前主流的 Java 專案都在使用 Spring Boot,那麼我們就來在 Spring Boot 中整合 Redis。

Spring Boot 使用“約定大於配置”的方式逐步的取代了早起通過 XML 進行配置的方式,使得在 Spring Boot 中整合各種庫或者依賴都非常的方便。在我們建立 Spring Boot 專案時,選擇相關的 Starter 時,在 “NoSQL” 中把 “Spring Data Redis” 項勾選即可

。這樣就會在 pom 檔案中新增相關的依賴,依賴如下:

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-data-redisartifactId>dependency>

有了 Redis 的依賴之後,我們就可以在專案中很容易的使用 Redis 的 API 來對 Redis 進行操作了。

Redis API 介紹

Spring Boot 提供的 Redis API 分為 高階 API低階 API

高階 API 是經過一定封裝後的 API,而低階 API 的使用和直接使用 Redis 的命令差不多

高階 API 提供了兩個類可以供我們使用,分別是 RedisTemplate 和 StringRedisTemplateStringRedisTemplate 繼承自 RedisTemplate,StringRedisTemplate 的序列化方式與 RedisTemplate 的序列化的方式不同。具體在使用上的差別不是特別明顯,但是資料在儲存到 Redis 中的時候,因為序列化方式的不同,會有一定的差別

低階 API 其實也是通過 RedisTemplate 或 StringRedisTemplate 來進行獲取。低階 API 的方法和 Redis 的命令差不多

Redis 高階 API 使用

先來看看 高階 API 的使用方法,具體就是 RedisTemplate 和 StringRedisTemplate 兩個類的使用。這裡不解釋具體過多的原理,主要來看看它們 API 的使用,與儲存的不同。

我們來建立一個 TestRedis 的類,並通過註解將其宣告為一個 Component,並注入 RedisTemplate 和 StringRedisTemplate 兩個類,程式碼如下。

@Componentpublic class TestRedis{    @Autowired    RedisTemplate redisTemplate;    @Autowired    StringRedisTemplate stringRedisTemplate;    public void redis(){            }}

我們對 Redis 的所有操作就在這個類中完成。由於我們對專案中沒有引入 SpringMVC 等,因此,測試 TestRedis 就直接通過 Spring Boot 的啟動類來直接進行呼叫,啟動類的程式碼如下:

public static void main(String[] args){    ConfigurableApplicationContext run = SpringApplication.run(SpringbootRedisApplication.class, args);    TestRedis bean = run.getBean(TestRedis.class);    bean.redis();}

我們接著來測試一下 RedisTemplate 這個類,用它來進行值為字串的操作,程式碼如下:

public void testRedisTemplate(){    ValueOperations valueOperations = redisTemplate.opsForValue();    valueOperations.set("key1", "value1");    valueOperations.set("key2", "哈哈");    System.out.println(valueOperations.get("key1"));    System.out.println(valueOperations.get("key2"));}

我們通過 redisTemplate 的 opsForValue 得到一個 ValueOperations 的例項,然後通過它來操作 Redis 的字串型別。使用它的 set 方法添加了 key1 和 key2 兩個鍵值對。然後,通過它的 get 方法又讀取了這兩個鍵對應的值。通過控制檯的輸出也可以看出,操作是成功的,控制檯輸出如下:

testRedisTemplate...value1哈哈

雖然在程式碼中操作是沒問題的,但是,我們通過 Redis 的客戶端來進行檢視一下。

127.0.0.1:6379> keys *1) "\xac\xed\x00\x05t\x00\x04key2"2) "\xac\xed\x00\x05t\x00\x04key1"127.0.0.1:6379> get \xac\xed\x00\x05t\x00\x04key2(nil)

從 Redis 的客戶端檢視,看到有一些 16 進位制的字元,而且也不方便我們進行 get 操作。我們換一種啟動 Redis 客戶端的方式,在啟動 Redis 客戶端時,我們來加一個 --raw 的引數,再來檢視我們寫入的鍵值對,如下:

[[email protected] ~]# redis-cli --raw127.0.0.1:6379> keys *��tkey2��tkey1

可以看到,在鍵的前面仍然有一些“奇怪”的字元,這些奇怪的字元就是前面看到的那些 16 進位制字元。我們來換 StringRedisTemplate 進行相同的操作,程式碼如下:

public void testStringRedisTemplate(){    ValueOperations stringStringValueOperations = stringRedisTemplate.opsForValue();    stringStringValueOperations.set("key3", "value3");    stringStringValueOperations.set("key4", "哈哈");    System.out.println(stringStringValueOperations.get("key3"));    System.out.println(stringStringValueOperations.get("key4"));}

我們把前面程式碼註釋掉,直接執行我們現在的程式碼,執行結果如下。

testStringRedisTemplate...value3哈哈

我們在到 Redis 中看一下,如下:

127.0.0.1:6379> keys *key4key3127.0.0.1:6379> get key4哈哈127.0.0.1:6379> get key3value3

使用 RedisTemplate 和 StringRedisTemplate 之所以有所差異,是因為 StringRedisTemplate 在對 Key 和 Value 進行序列化時,都使用字串的方式進行序列化。因此,我們選擇 StringRedisTemplate 會方便一些。

Redis 低階API 使用

Redis 的 低階 API 使用是相對比較麻煩的。同樣使用一個例子來進行檢視。

public void testLowApi(){    RedisConnection connection = stringRedisTemplate.getConnectionFactory().getConnection();    connection.set("key5".getBytes(), "value5".getBytes());    connection.set("key6".getBytes(), "哈哈".getBytes());    byte[] bytes = connection.get("key5".getBytes());    System.out.println(new String(bytes));    byte[] bytes1 = connection.get("key6".getBytes());    System.out.println(new String(bytes1));}

執行程式碼,輸出如下:

testLowApi...value5哈哈

同樣的,我們到 Redis 的客戶端中進行檢視,如下:

127.0.0.1:6379> keys *key4key3key6key5127.0.0.1:6379> get key5value5127.0.0.1:6379> get key6哈哈

看著效果也是不錯的。不過它的操作過於繁瑣,我們還是不考慮使用它。雖然不考慮使用它,但是簡單的瞭解還是要有的。

Redis 高階API 操作 Hash

在 Redis 中,使用雜湊結構還是比較常見的。這裡給出一個簡單的操作雜湊結構的程式碼,我們進行一些簡單的操作,程式碼如下:

public void optHash(){    HashOperations<String, Object, Object> stringObjectObjectHashOperations = stringRedisTemplate.opsForHash();    stringObjectObjectHashOperations.put("no1", "name", "zhangsan");    stringObjectObjectHashOperations.put("no1", "age", 22);System.out.println(stringObjectObjectHashOperations.entries("no1"));}

我們來執行一下程式碼,執行結果如下:

optHash...Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String  at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36)  at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:185)  at org.springframework.data.redis.core.DefaultHashOperations.put(DefaultHashOperations.java:189)  at cn.coderup.TestRedis.optHash(TestRedis.java:71)  at cn.coderup.TestRedis.redis(TestRedis.java:32)  at cn.coderup.SpringbootRedisApplication.main(SpringbootRedisApplication.java:16)

可以看到,執行程式碼時報錯了,原因是在進行轉換時發生了異常通過異常丟擲的資訊可以看出,在 StringRedisSerializer 進行序列化時發生的異常,這個問題是,在我們程式碼中的第二個 put 方法時傳入了一個整型的 22 進去,這裡將它改為字串的 22,修改後的程式碼如下:

stringObjectObjectHashOperations.put("no1", "age", "22");

執行修改後的程式碼,檢視輸出結果:

optHash...{name=zhangsan,age=22}

Redis 高階 API 操作類

上面的程式碼雖然完成了對雜湊的操作,但是略顯繁瑣,類似上面的操作我們實際中並不會去逐個的進行 put 操作,更多的應該是將一個實體類儲存到 Redis 的雜湊型別中。我們通過程式碼演示一下。

先定義一個學生類,定義如下:

public class Student{    private String name;    private Integer age;

我省去了程式碼中的 getter 和 setter 方法,大家補全即可。除此而外,需要引入另外一個依賴,用於將物件轉為 HashMap 或 HashMap 轉換為物件。pom檔案中新增的依賴如下:

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-jsonartifactId>dependency>

有了上面的依賴以後,我們來接著完成程式碼,首先將 ObjectMapper 進行注入:

@AutowiredObjectMapper objectMapper;

注入 ObjectMapper 後,我們來將實體類寫入 Redis 的雜湊型別中,程式碼如下:

public void optHashForObj(){    Student student = new Student();    student.setName("zhangsan");    student.setAge(20);    Jackson2HashMapper jackson2HashMapper = new Jackson2HashMapper(objectMapper, false);    HashOperations<String, Object, Object> stringObjectObjectHashOperations = stringRedisTemplate.opsForHash();    // 物件轉Mapper    stringObjectObjectHashOperations.putAll("no2", jackson2HashMapper.toHash(student));    Map<Object, Object> no2 = stringObjectObjectHashOperations.entries("no2");    // Map轉物件    Student student1 = objectMapper.convertValue(no2, Student.class);    System.out.println(student1.getName());    System.out.println(student1.getAge());}

這樣我們的程式碼看似就完成了,那麼我們執行一下,看會輸出什麼內容,輸出如下:

optHashForObj...Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String  at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36)  at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:185)  at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:147)  at cn.coderup.TestRedis.optHashForObj(TestRedis.java:98)  at cn.coderup.TestRedis.redis(TestRedis.java:44)  at cn.coderup.SpringbootRedisApplication.main(SpringbootRedisApplication.java:16)

可以看出,又丟擲了異常,問題同樣是因為我們的 Student 類中的 age 屬性是 Integer 型別。那麼,是不是需要我們將 Integer 型別換成 String 型別呢?如果真的需要將 Integer 型別全部修改為 String 型別的話,那麼在實際的專案中就是一場災難了。那麼具體怎麼辦呢?其實只要修改 Hash 的序列化器,我們在 stringRedisTemplate.opsForHash()這句程式碼上增加一句程式碼,程式碼如下:

stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));

再次執行我們的程式碼,執行結果如下:

optHashForObj...zhangsan20

通過 Redis 的客戶端來檢視我們寫入的 Hash 型別的值,也是沒有任何問題的。

全域性的 Redis 配置

在上面的程式碼中,可以通過設定 Hash 型別的序列化器從而方便的使用 putAll() 方法將一個類寫入 Redis 中。但是,每次這樣的寫入都會特別的繁瑣,我們定義一個全域性的 Redis 的配置類,以後就無需每次使用都進行序列化器的設定了。

我們新增一個 RedisConfig 類,程式碼如下:

@Configurationpublic class RedisConfig{    @Autowired    RedisConnectionFactory redisConnectionFactory;    @Bean    public StringRedisTemplate getStringRedisTemplate()    {        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);        stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));        return stringRedisTemplate;    }}

有了上面的程式碼,我們就無需每次都設定序列化器了。為了進行測試,我們刪掉前面程式碼中設定序列化器的程式碼,然後再執行程式碼看是否報錯,結果是沒有問題,不會報錯。

總結

關於在 Spring Boot 中簡單整合Redis 的方法就基本完成了。當然了,這裡沒有介紹具體如何操作各種資料結構的方法,以及一些 Redis 的實際使用場景,後續再進行介紹吧。

f42b30012752c4bb9beb677919e1dfa8.png