Redis的Java客戶端-Jedis 在Redis官網中提供了各種語言的客戶端,地址:https://redis.io/docs/clients/ 其中Java客戶端也包含很多: 標記為❤的就是推薦使用的java客戶端,包括: Jedis和Lettuce:這兩個主要是提供了Redis命令對應的AP ...
Redis的Java客戶端-Jedis
在Redis官網
中提供了各種語言的客戶端,地址:https://redis.io/docs/clients/
其中Java客戶端也包含很多:
標記為❤
的就是推薦使用的java客戶端,包括:
- Jedis和Lettuce:這兩個主要是提供了Redis命令對應的API,方便我們操作Redis,而SpringDataRedis是對這兩種做了抽象和封裝。
- Redisson:是在Redis基礎上實現了分散式的可伸縮的java數據結構,例如Map.Queue等,而且支持跨進程的同步機制:Lock.Semaphore等待,比較適合用來實現特殊的功能需求。
Jedis快速入門
入門案例詳細步驟
案例分析:
0)創建工程:
1)引入依賴:
<!--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>5.7.0</version>
<scope>test</scope>
</dependency>
2)建立連接
新建一個單元測試類,內容如下:
private Jedis jedis;
@BeforeEach
void setUp() {
// 1.建立連接
// jedis = new Jedis("192.168.150.101", 6379);
jedis = JedisConnectionFactory.getJedis();
// 2.設置密碼
jedis.auth("123321");
// 3.選擇庫
jedis.select(0);
}
3)測試:
@Test
void testString() {
// 存入數據
String result = jedis.set("name", "虎哥");
System.out.println("result = " + result);
// 獲取數據
String name = jedis.get("name");
System.out.println("name = " + name);
}
@Test
void testHash() {
// 插入hash數據
jedis.hset("user:1", "name", "Jack");
jedis.hset("user:1", "age", "21");
// 獲取
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}
4)釋放資源
@AfterEach
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
Jedis連接池
Jedis本身是線程不安全的,並且頻繁的創建和銷毀連接會有性能損耗,因此推薦大家使用Jedis連接池代替Jedis的直連方式
有關池化思想,並不僅僅是這裡會使用,很多地方都有,比如說我們的資料庫連接池,比如我們tomcat中的線程池,這些都是池化思想的體現。
創建Jedis的連接池
public class JedisConnectionFacotry {
private static final JedisPool jedisPool;
static {
//配置連接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setMaxWaitMillis(1000);
//創建連接池對象
jedisPool = new JedisPool(poolConfig,
"192.168.150.101",6379,1000,"123321");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
代碼說明:
-
1) JedisConnectionFacotry:工廠設計模式是實際開發中非常常用的一種設計模式,我們可以使用工廠,去降低代的耦合,比如Spring中的Bean的創建,就用到了工廠設計模式
-
2)靜態代碼塊:隨著類的載入而載入,確保只能執行一次,在載入當前工廠類的時候,就可以執行static的操作完成對 連接池的初始化
-
3)最後提供返回連接池中連接的方法.
改造原始代碼
代碼說明:
1.在完成了使用工廠設計模式來完成代碼的編寫之後,獲得連接時,就可以通過工廠來獲得。
而不用直接去new對象,降低耦合,並且使用的還是連接池對象。
2.當我們使用了連接池後,當我們關閉連接其實並不是關閉,而是將Jedis還回連接池的。
@BeforeEach
void setUp(){
//建立連接
/*jedis = new Jedis("127.0.0.1",6379);*/
jedis = JedisConnectionFacotry.getJedis();
//選擇庫
jedis.select(0);
}
@AfterEach
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
Redis的Java客戶端-SpringDataRedis
SpringData是Spring中數據操作的模塊,包含對各種資料庫的集成,其中對Redis的集成模塊就叫做SpringDataRedis,
官網地址
:https://spring.io/projects/spring-data-redis
- 提供了對不同Redis客戶端的整合(Lettuce和Jedis)
- 提供了RedisTemplate統一API來操作Redis
- 支持Redis的發佈訂閱模型
- 支持Redis哨兵和Redis集群
- 支持基於Lettuce的響應式編程
- 支持基於JDK.JSON.字元串.Spring對象的數據序列化及反序列化
- 支持基於Redis的JDKCollection實現
SpringDataRedis中提供了RedisTemplate工具類,其中封裝了各種對Redis的操作。並且將不同數據類型的操作API封裝到了不同的類型中:
快速入門
SpringBoot已經提供了對SpringDataRedis的支持,使用非常簡單:
- 導入pom坐標
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangsan</groupId>
<artifactId>redis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--Jackson依賴-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件
spring:
redis:
host: 192.168.150.101
port: 6379
password: 123321
lettuce:
pool:
max-active: 8 #最大連接
max-idle: 8 #最大空閑連接
min-idle: 0 #最小空閑連接
max-wait: 100ms #連接等待時間
測試代碼
@SpringBootTest
class RedisDemoApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
void testString() {
// 寫入一條String數據
redisTemplate.opsForValue().set("name", "虎哥");
// 獲取string數據
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
}
貼心小提示:SpringDataJpa使用起來非常簡單,記住如下幾個步驟即可
SpringDataRedis的使用步驟:
- 引入spring-boot-starter-data-redis依賴
- 在application.yml配置Redis信息
- 註入RedisTemplate
數據序列化器
RedisTemplate可以接收任意Object作為值寫入Redis:
只不過寫入前會把Object序列化為位元組形式,預設是採用JDK序列化,得到的結果是這樣的:
缺點:
- 可讀性差
- 記憶體占用較大
可以自定義RedisTemplate的序列化方式,代碼如下:
@Configuration
public class RedisConfig {
@Bean
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);
// 返回
return template;
}
}
這裡採用了JSON序列化來代替預設的JDK序列化方式。最終結果如圖:
整體可讀性有了很大提升,並且能將Java對象自動的序列化為JSON字元串,並且查詢時能自動把JSON反序列化為Java對象。不過,其中記錄了序列化時對應的class名稱,目的是為了查詢時實現自動反序列化。這會帶來額外的記憶體開銷。
StringRedisTemplate
儘管JSON的序列化方式可以滿足需求,但依然存在一些問題,如圖:
為了在反序列化時知道對象的類型,JSON序列化器會將類的class類型寫入json結果中,存入Redis,會帶來額外的記憶體開銷。
為了減少記憶體的消耗,可以採用手動序列化的方式,換句話說,就是不藉助預設的序列化器,而是控制序列化的動作,同時,只採用
String的序列化器,這樣,在存儲value時,就不需要在記憶體中就不用多存儲數據,從而節約記憶體空間
這種用法比較普遍,因此SpringDataRedis就提供了RedisTemplate的子類:StringRedisTemplate,它的key和value的序列化方式預設就是String方式。
省去了自定義RedisTemplate的序列化方式的步驟,而是直接使用:
@SpringBootTest
class RedisStringTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testString() {
// 寫入一條String數據
stringRedisTemplate.opsForValue().set("verify:phone:13600527634", "124143");
// 獲取string數據
Object name = stringRedisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
// 創建對象
User user = new User("虎哥", 21);
// 手動序列化
String json = mapper.writeValueAsString(user);
// 寫入數據
stringRedisTemplate.opsForValue().set("user:200", json);
// 獲取數據
String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
// 手動反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println("user1 = " + user1);
}
}
此時再來看一看存儲的數據,會發現那個class數據已經不在了,節約了空間
最後小總結:
RedisTemplate的兩種序列化實踐方案:
-
方案一:
- 自定義RedisTemplate
- 修改RedisTemplate的序列化器為GenericJackson2JsonRedisSerializer
-
方案二:
- 使用StringRedisTemplate
- 寫入Redis時,手動把對象序列化為JSON
- 讀取Redis時,手動把讀取到的JSON反序列化為對象
Hash結構操作
@SpringBootTest
class RedisStringTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testHash() {
stringRedisTemplate.opsForHash().put("user:400", "name", "虎哥");
stringRedisTemplate.opsForHash().put("user:400", "age", "21");
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:400");
System.out.println("entries = " + entries);
}
}
更多最新文章:【傳送門】********** 如果您認為這篇文章還不錯或者有所收穫,請點擊右下角的【推薦】/【贊助】按鈕,因為您的支持是我繼續寫作,分享的最大動力! **********
作者:講文張字
出處:https://www.cnblogs.com/zhangwencheng
版權:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出 原文鏈接