??各位小伙伴們大家好,歡迎來到這個小扎扎的Redis 6專欄,在這個系列專欄中我對B站黑馬的Redis教程進行一個總結,鑒于 看到就是學到、學到就是賺到 精神,這波依然是血賺 ┗|`O′|┛
💡Redis知識點速覽
- 🍖 Jedis的使用
- 🥩 Jedis快速入門
- 🥩 Jedis連接池
- 🍖 SpringBoot整合RedisTemplate
- 🥩 自定義配置RedisTemplate
- 🥩 StringRedisTemplate
??我們知道,redis是一個很強大的NoSQL數據庫,從上面那一張圖就可以看出來它分別擁有支持多種語言的客戶端,Java語言就是其中之一。上面的截圖來源于官網:https://redis.io/docs/clients/
??點開Java可以看到,官方推薦我們使用前三種Redisson、Jedis、Lettuce客戶端,那么他們分別有何優缺點,我們又該如何選擇呢?
- Redisson是一個基于Redis實現的分布式、可伸縮的Java數據結構集合。包含了諸如Map、Queue、Lock、 Semaphore、AtomicLong等強大功能
- Jedis以Redis命令作為方法名稱,學習成本低,簡單實用。但是Jedis實例是線程不安全的,多線程環境下必須需要使用連接池來連接
- Lettuce是基于Netty實現的,支持同步、異步和響應式編程方式,并且是線程安全的。支持Redis的哨兵模式、集群模式和管道模式
??基于目前的使用狀況,我們先學習Jedis的原生API,然后再學習Spring整合Spring Data Redis框架,該框架底層很好的兼容了Jedis和Lettuce
🍖 Jedis的使用
🥩 Jedis快速入門
??官網地址: https://github.com/redis/jedis
第一步: 導依賴
<!--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>
</dependency>
第二步: 與redis建立連接,在Java中的體現就是實例化一個Jedis對象,構造器的參數需要虛擬機的ip地址,可以使用如下命令查看
/*** 與Redis建立連接 @BeforeEach表示每個方法執行之前都需要執行該方法* @Param void* @return*/
@BeforeEach
void setUp() {// 建立連接jedis = new Jedis("你的虛擬機ip", 6379);// 設置redis的密碼jedis.auth("你的redis密碼");// 選擇使用的庫 默認是0號庫jedis.select(0);
}
第三步: 測試各種添加查詢操作,API的名和redis的命令一致,其他操作參考redis的命令
/** * K-V的測試* @Param void * @return */
@Test
void testHash() {Map<String, String> map = new HashMap<String, String>();map.put("id", "1");map.put("username", "zhagnsan");map.put("age", "20");// 存入數據jedis.hset("user", map);// 獲取命令Set<String> userKeys = jedis.hkeys("user");List<String> userValues = jedis.hvals("user");// 輸出獲取的結果System.out.println(userKeys);System.out.println("============================");System.out.println(userValues);
}
第四步: 斷開連接
/*** 關閉連接 @AfterEach表示每個方法執行之后都需要執行該方法* @Param void* @return*/
@AfterEach
void tearDown() {if (jedis != null) {jedis.close();}
}
redis.clients.jedis.exceptions.JedisConnectionException: Failed to create socket.
??如果報上面的錯誤連接不上的話,可以參考這篇博客https://blog.csdn.net/qq_44624536/article/details/120213607,如果還是無法解決的話,很有可能就是虛擬機的防火墻沒有關閉,可以使用如下命令查看并關閉一下(我的就是這個錯誤原因)
# 查看防火墻狀態的命令
systemctl status firewalld
# 關閉防火墻的命令
systemctl stop firewalld
運行結果
🥩 Jedis連接池
??上面說過Jedis本身是線程不安全的,如果在多線程并發操作下極有可能出現線程安全問題,因此在并發的環境下,一定要為每一個線程創建一個獨立的線程對象。但是頻繁的創建銷毀連接會導致性能損耗,因此需要使用到Jedis連接池來代替Jedis的直接連接方式。
第一步: 使用工具類創建并配置連接池對象,并使用靜態方法返回連接
public class JedisConnectionFactory {private static final JedisPool JEDIS_POOL;static {// 配置連接池JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();// 設置最大連接數、最大空閑連接、最小空閑連接、設置無連接的等待時間(毫秒為單位)jedisPoolConfig.setMaxTotal(8);jedisPoolConfig.setMaxIdle(8);jedisPoolConfig.setMinIdle(0);jedisPoolConfig.setMaxWaitMillis(1000);// 創建連接池對象JEDIS_POOL = new JedisPool(jedisPoolConfig, "你的虛擬機ip", 6379, 1000, "你的redis密碼");}public static Jedis getJedis() {return JEDIS_POOL.getResource();}
}
第二步: 調用靜態方法建立連接即可,剩下的操作都一樣
@BeforeEach
void setUp() {// 建立連接jedis = JedisConnectionFactory.getJedis();// 選擇使用的庫 默認是0號庫jedis.select(0);
}
🍖 SpringBoot整合RedisTemplate
🥩 自定義配置RedisTemplate
第一步: 導入SpringBoot整合RedisTemplate的依賴,連接池的依賴,SpringBoot項目不用指定技術版本,繼承使用父工程中已經配置好的版本
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
第二步: 配置信息
spring:redis:host: 你的虛擬機ipport: 6379password: 你的redis密碼lettuce:pool:max-active: 8max-idle: 8min-idle: 0max-wait: 1000
第三步: 直接注入redisTemplate對象,使用它內部的API
@Autowired
private RedisTemplate redisTemplate;@Test
void contextLoads() {redisTemplate.opsForValue().set("name", "zhangsan");Object name = redisTemplate.opsForValue().get("name");System.out.println("name ==>" + name);
}
結果顯示并沒有問題,可以正常的存入讀出但是切換到redis中查看就有問題了,沒有name這個key,但是有一個亂碼的K-V生成,這是什么原因呢?是因為redisTemplate底層將這個K-V當做對象進行了默認的jdk序列化操作
jdk序列化差生的結果會有很多的問題,結果可讀性很差,短字符串的話又會很占用內存空間,于是我們可以選擇使用其他的序列化方式,使用配置類替代默認的序列化配置
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {// 創建RedisTemple對象RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();// 設置連接工廠redisTemplate.setConnectionFactory(redisConnectionFactory);// 創建JSON序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 設置K序列化redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());// 設置V序列化redisTemplate.setValueSerializer(jsonRedisSerializer);redisTemplate.setHashValueSerializer(jsonRedisSerializer);// 返回RedisTemplate對象return redisTemplate;}
}
由于使用到了JSON所以需要導入相關依賴,如果導入mvc的依賴的話會默認導入JSON但是,我們的項目沒有導MVC也沒有JSON,所以需要導一下
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>
按理來說,value也可以是一個對象,redisTemplate會將其序列化為JSON對象進行存儲
@Test
void test01() {redisTemplate.opsForValue().set("user", new User("zhangsan", 20));Object name = redisTemplate.opsForValue().get("name");System.out.println("user ==> " + name);
}
🥩 StringRedisTemplate
??由于上面使用配置類自定義序列化的方式,導致序列化之后的字符串會帶",而且Jason對象序列化之后會帶有類的全限定名,數據量大了之后也會影響到存儲的性能。于是出現了StringRedisTemplate,這種模板很好的解決了上述問題,但是需要我們手動的將對象進行序列化和反序列化
@SpringBootTest
public class StringRedistemplateTest {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid contextLoads() {stringRedisTemplate.opsForValue().set("name", "lisi");Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name ==>" + name);}// 創建ObjectMapper對象用于序列化和反序列化private static final ObjectMapper MAPPER = new ObjectMapper();@Testvoid test01() throws JsonProcessingException {// 創建user對象 并序列化對象User user = new User("zhangsan", 20);String userJson = MAPPER.writeValueAsString(user);// 寫數據stringRedisTemplate.opsForValue().set("user", userJson);// 讀數據并反序列化輸出String res = stringRedisTemplate.opsForValue().get("user");User jsonUser = MAPPER.readValue(res, User.class);System.out.println("user ==> " + jsonUser);}
}
@Test
void testHash() {stringRedisTemplate.opsForHash().put("user01", "name", "lisi");stringRedisTemplate.opsForHash().put("user01", "age", "21");Map<Object, Object> user01 = stringRedisTemplate.opsForHash().entries("user01");System.out.println(user01);
}