目錄
1、Jedis客戶端
1.1使用過程
2、SpringDataRedis
2.1 SpingDataRedis介紹
2.2SpringDataRedis快速入門
2.3RedisTemplate的RedisSerializer
2.3.1RedisTemplate中JDK序列化局限性
2.3.2方式一:改變RedisTemplate的序列化方式
2.3.3RedisTemplate存儲一個對象
2.3.4 方式二:StringRedisTemplate
1、Jedis客戶端
1.1使用過程
1、新建一個maven項目

2、引入依賴
<!--jedis-->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version>
</dependency><!--單元測試-->
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope>
</dependency>
3、建立連接
@BeforeEach
void setUp(){//1、建立連接jedis = new Jedis("120.53.240.101",6379);//2、設置密碼jedis.auth("123321");//3、選擇庫jedis.select(5);
}
注意!!Jedis本身是線程不安全的,并且頻繁的創建和銷毀連接會有性能損耗,因此推薦使用Jedis連接池代替Jedis的直連方式
package com.tang.util;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;public class JedisConnectionFactory {// Jedis連接池對象private static JedisPool jedisPool;static {//配置連接池JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();// 最大連接數jedisPoolConfig.setMaxTotal(8);// 最大空閑連接數,最多可創建的連接jedisPoolConfig.setMaxIdle(8);// 最小空閑連接數,最少可創建的連接數,長時間沒鏈接時就銷毀至0,當然也可以預備一些連接jedisPoolConfig.setMinIdle(0);//默認值是-1,表示沒有限制// 設置最長等待時間(ms),連接池里沒有連接時就等待,超過這個時間就拋異常jedisPoolConfig.setMaxWaitMillis(1000);//創建連接池對象,1000是連接超時時間jedisPool = new JedisPool(jedisPoolConfig,"120.53.240.101", 6379, 1000, "123321");}// 獲取Jedis實例public static Jedis getJedis() {return jedisPool.getResource();}}
在測試類中,連接直接從工具類里拿
@BeforeEach
void setUp(){//1、建立連接jedis = JedisConnectionFactory.getJedis();//2、選擇庫jedis.select(6);
}
4、測試string
set類型
@Test
void testString(){ //存入數據String result = jedis.set("name","tang");System.out.println("result="+result);//獲取數據String name = jedis.get("name");System.out.println("name="+name);
}
Hash類型
@Test
void testHash(){jedis.hset("user","name","tang");jedis.hset("user","age","22");Map<String, String> user = jedis.hgetAll("user");System.out.println(user);
}
5、釋放資源
@AfterEach
void tearDown(){//健壯性判斷,關閉鏈接if(jedis != null){jedis.close();}
}
6、結果返回
string

hash

2、SpringDataRedis
2.1 SpingDataRedis介紹
SpringData是Spring中數據操作的模塊,包含對各種數據庫的集成,其中對Redis的集成模塊就叫做SpringDataRedis,
官網Spring Data Redis
-
提供了對不同Redis客戶端的整合(Lettuce和jedis)
-
提供了RedisTemplate統一API來操作Redis
-
支持Redis的發布訂閱模型
-
支持Redis哨兵和Redis集群
-
支持基于Lettuce的響應式編程
-
支持基于JDK、JSON、字符串、Spring對象的數據序列化及反序列化
2.2SpringDataRedis快速入門
????????SPringDataRedis中提供了RedisTemplate工具類,其中封裝了各種對Redis的操作。并且將不同數據類型的操作API封裝到了不同的類型中:

SpringBoot已經提供了對SpringDataRedis的支持,使用非常簡單:
新建項目,我們在這創建一個SpringBoot項目
可以提前勾選幾個依賴。(注意!!在我這,這個SpringBoot版本進去要改一下,不然會因為版本過高等問題出錯)

1、導入依賴
<!--Redis依賴-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--連接池依賴-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.11.1</version>
</dependency>
2、配置文件
spring:redis:host: 120.53.240.101port: 6379password: 123321lettuce:pool:max-active: 8 #最大連接max-idle: 8 #最大空閑連接min-idle: 0 #最小空閑連接max-wait: 100 #最大等待時間
3、注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
4、編寫測試
在這里我們看到,set()并沒有強硬要求我們必須傳入字符串參數

@Test
void testString() {//寫入一條String類型數據redisTemplate.opsForValue().set("name","tang");//讀取一條String類型數據Object name = redisTemplate.opsForValue().get("name");System.out.println("name="+name);
}

2.3RedisTemplate的RedisSerializer
2.3.1RedisTemplate中JDK序列化局限性
當我們嘗試用SpringDataRdies修改某個鍵的值時,會發現如下情景:
我們先在數據庫中存入鍵name,并把他的value設為Jack

然后我們調用SpringDataRedis,將鍵name的value設置為tang

得到如下返回結果

回到我們的redis命令行去get name,

我們會發現name的值并未改變
獲取一下全部的keys,出現一串不知名的key。

我們來get一下這個key,返回的還是一串字符

為什么會這樣子?
????????我們看set方法我們發現他接受的并不是字符串,它可以接收任何類型的對象,然后轉換成redis可以處理的字節(JDK的序列化工具ObjectOutputStream)再寫入redis。

debug進入set方法,我們發現它最終進入到了JdkSerializer

最后調用ObjectOutputStream

這樣寫有什么問題?
可讀性差
內存占用較大
容易出現bug:不是修改,因為key也被序列化
2.3.2方式一:改變RedisTemplate的序列化方式
crtl+H查看RedisSerializer的subTypes

JdkSerializationRedisSerializer我們已經發現它并不好用。
StringRedisSerializer是專門處理字符串的序列化工具getbytes:當key或者hashkey是字符串類型的時候可以使用。
GenericJackson2JsonRedisSerializer這是一個轉JSON字符串的序列化工具:適合于value使用
我們手寫一個工具類,自定義RedisTemplate的序列化方式
package com.tang.springdataredisdemo.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;
import sun.net.www.content.text.Generic;/*** 注冊一個配置類,實現自定義Redis序列化* @author tang* @date 2021-06-07 16:05* @desc*/
@Configuration
public class RedisConfig {@Bean// 自定義Redis序列化public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {//創建RedisTemplate對象RedisTemplate<String, Object> template = new RedisTemplate<>();//設置連接工廠template.setConnectionFactory(connectionFactory);//創建JSON的序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();//設置key序列化方式template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());//設置value序列化方式template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);//返回RedisTemplate對象return template;}
}
添加這個配置類后,我們對測試的部分進行一些修改,改為泛型格式

@Autowired
private RedisTemplate<String,Object> redisTemplate;
還需要添加一個依賴
<!--Jackson依賴-->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>
idea里結果返回如下:

現在去redis數據庫里看一下,沒問題了!

2.3.3RedisTemplate存儲一個對象
創建一個User類
package com.tang.springdataredisdemo.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private String name;private Integer age;
}
編寫測試案例
@Test
void testObject() {User user = new User("tang", 18);//寫入一條Object類型數據redisTemplate.opsForValue().set("user:100",user);//讀取一條Object類型數據(直接強轉)User user1 =(User) redisTemplate.opsForValue().get("user:100");System.out.println("user="+user1);
}
結果返回如下

在數據庫中,自動轉化為JSON風格的數據存儲起來

圖片上的JSON中還有一個“@class”,這個字段幫助將json格式反序列化為對應的對象(反射)
但這會帶來額外的內存開銷
2.3.4 方式二:StringRedisTemplate
在2.3.3中我們發現使用GenericJackson2JsonRedisSerializer會產生額外的字段,消耗了很大一部分的內存空間。
為了節省內存空間,我們并不會使用JSON序列化器來處理value,而是統一使用String序列化器,要求只能存儲String類型的key和value。當需要存儲Java對象時,手動完成對象的序列化和反序列化。
Spring默認提供了一個StringRedisTemplate類,他的key和value的序列化方式默認就是String方式。省去了我們自定義的時間。
在測試類注入
@Autowired
private StringRedisTemplate stringRedisTemplate;
修改測試用例,在存入對象的部分多了一個手動序列化和反序列化的過程
@Test
void testString() {//寫入一條String類型數據stringRedisTemplate.opsForValue().set("name","tang");//讀取一條String類型數據Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name="+name);
}
@Test
void testHash(){stringRedisTemplate.opsForHash().put("user:200","name","tang");stringRedisTemplate.opsForHash().put("user:200","age","18");Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:200");System.out.println("entries="+entries);}
//序列化工具,使用fastjson也是可以的
private static final ObjectMapper objectMapper = new ObjectMapper();@Test
void testObject() throws JsonProcessingException {//創建對象User user = new User("tang", 18);//手動序列化String json = objectMapper.writeValueAsString(user);//寫入一條Object類型數據stringRedisTemplate.opsForValue().set("user:100",json);//讀取一條Object類型數據(直接強轉)String jsonUser =stringRedisTemplate.opsForValue().get("user:100");//手動反序列化objectMapper.readValue(jsonUser,User.class);System.out.println("user="+jsonUser);
}
結果顯示
