最近在學習redis,把redis單機數據庫的基礎知識看的差不多了,準備用SpringBoot整合實踐一下。
最開始去看spring官網關於spring-data-redis的文檔(英文不太好,結合有道看了幾個重點的地方,但是上面也沒有具體說到
這個代碼該怎麼寫)。
然後百度了幾篇博文,都看了一遍,大致理清網上作者們的思路。關於SpringBoot整合redis的文章一般有這麼這種:
- 直接引入redis-client的客戶端來使用的。
- 引入spring-boot-starter-data-redis來使用的(這是Spring推薦的方式,幫助我們封裝了redis-client)。
- 關於Spring Cache和redis做整合的。
第三種可以暫時不關注它,第三種的使用應該建立在先會第一種或者第二種通過代碼手動的去操作redis的基礎上。
第一種是直接使用redis-client,在Spring的項目中不推薦使用這種方式,因爲redis的客戶端實在太多了,各個客戶端的語法可能
不太一樣,不利於後期更換客戶端。
以下是用Java實現的Redis客戶端
可以看到,光Java的客戶端就有這麼多。Redis官方推薦的有Jedis、Lettuce和Redisson。
而第二種就是今天要講的,Spring幫我們封裝了Lettuce和Jedis兩種客戶端,併爲開發者提供了更高級的一些API。
下面開始整合(關於SpringBoot和Redis我就假設各位讀者大人都是已知的)
引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redis依賴commons-pool 這個依賴一定要添加 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
這裏要說明一下,我之前在網上看了一些文章的依賴是spring-boot-starter-redis,這是老版本的。另外需要注意的是2.x版本以前的
Redis客戶端默認是用Jedis來實現的,而在2.x版本則是用Lettuce來實現的,所以在配置上面有所不同。
SpringBoot配置文件
1 server: 2 port: 80 3 spring: 4 cache: 5 type: 6 redis 7 redis: 8 host: l27.0.0.1 9 port: 6379 10 # 密碼,如果沒有設置可以不填寫,設置密碼請看redis.conf的requirepass參數 11 password: 123456 12 # 如果使用的jedis 則將lettuce改成jedis即可 13 lettuce: 14 pool: 15 # 最大活躍鏈接數 默認8 16 max-active: 8 17 # 最大空閒連接數 默認8 18 max-idle: 8 19 # 最小空閒連接數 默認0 20 min-idle: 0
Spring Data Redis爲我們提供一個對象redisTemplate用於操作redis,下面是它的源碼
Spring默認爲我們實現了兩個對象redisTemplate和stringRedisTemplate,其中stringRedisTemplate是專門用來操作字符對象的,因爲在實際使用中,
用Redis來緩存字符串對象是更常見的場景。
我們就用redisTempate來編寫測試代碼
package com.example.redis;
import com.example.redis.domain.User;
import org.assertj.core.internal.bytebuddy.asm.Advice;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.Serializable;
import java.util.stream.IntStream;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisApplicationTests {
/*@Autowired
private RedisTemplate<String, Serializable> redisTemplate;*/
@Autowired
private RedisTemplate redisTemplate;
@Test
public void contextLoads() {
// 字符串測試
User user = new User();
user.setId(1L);
user.setName("小白一隻");
user.setAge(18);
redisTemplate.opsForValue().set("user", user);
User newUser = (User) redisTemplate.opsForValue().get("user");
System.out.println("get user :" + newUser);
// 列表測試
/*ListOperations<String, Serializable> listOperation = redisTemplate.opsForList();
IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));*/
}
}
執行成功,然後使用medis可視化工具去查看redis數據庫
注意是最後一個。發現居然亂碼,而且類型爲NONE,已經被清除掉了。
經過查閱得知,redisTemplate默認使用序列化器是JdkSerializationRedisSerializer,我們把它切換成GenericJackson2JsonRedisSerializer。
切換序列化器需要新建一個redisTemplate覆蓋原本的redisTemplate並且保留除了序列化器的其他屬性。以下是代碼實現:
1 package com.example.redis.config; 2 3 import org.springframework.boot.autoconfigure.AutoConfigureAfter; 4 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 8 import org.springframework.data.redis.core.RedisTemplate; 9 import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 10 import org.springframework.data.redis.serializer.StringRedisSerializer; 11 12 import java.io.Serializable; 13 14 @Configuration 15 @AutoConfigureAfter(RedisAutoConfiguration.class) 16 public class RedisConfig { 17 18 /** 19 * 配置自定義redisTemplate 20 */ 21 /*@Bean 22 RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { 23 24 RedisTemplate<String, Object> template = new RedisTemplate<>(); 25 template.setConnectionFactory(redisConnectionFactory); 26 27 //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值 28 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); 29 30 ObjectMapper mapper = new ObjectMapper(); 31 mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 32 mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 33 serializer.setObjectMapper(mapper); 34 35 template.setValueSerializer(serializer); 36 //使用StringRedisSerializer來序列化和反序列化redis的key值 37 template.setKeySerializer(new StringRedisSerializer()); 38 template.setHashKeySerializer(new StringRedisSerializer()); 39 template.setHashValueSerializer(serializer); 40 template.afterPropertiesSet(); 41 return template; 42 }*/ 43 44 /** 45 * 配置自定義redisTemplate 46 */ 47 @Bean 48 public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory redisConnectionFactory) { 49 RedisTemplate<String, Serializable> template = new RedisTemplate<>(); 50 template.setKeySerializer(new StringRedisSerializer()); 51 template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); 52 template.setConnectionFactory(redisConnectionFactory); 53 return template; 54 } 55 56 }
接下來修改測試代碼
1 package com.example.redis; 2 3 import com.example.redis.domain.User; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.boot.test.context.SpringBootTest; 8 import org.springframework.data.redis.core.RedisTemplate; 9 import org.springframework.test.context.junit4.SpringRunner; 10 11 import java.io.Serializable; 12 13 @RunWith(SpringRunner.class) 14 @SpringBootTest 15 public class RedisApplicationTests { 16 17 @Autowired 18 private RedisTemplate<String, Serializable> redisTemplate; 19 20 @Test 21 public void contextLoads() { 22 // 字符串測試 23 User user = new User(); 24 user.setId(1L); 25 user.setName("小白一隻"); 26 user.setAge(18); 27 redisTemplate.opsForValue().set("user", user); 28 User newUser = (User) redisTemplate.opsForValue().get("user"); 29 System.out.println("get user :" + newUser); 30 31 // 列表測試 32 /*ListOperations<String, Serializable> listOperation = redisTemplate.opsForList(); 33 IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));*/ 34 } 35 36 }
重新執行,執行結果如下:
查看redis數據庫:
這些對了,可以看到保存就是一段json字符串。
redis常用有五種數據類型,分別是
- String (字符串)
- List (列表)
- Set (集合)
- Sort Set(有序集合)
- Hash(字典)
可以使用type命令查看類型,object encoding查看編碼
關於redis對象的類型和編碼以及底層數據結構的關係就需要去看看書籍了
在代碼裏面直接使用
分別對應不同類型進行操作,就行了。
我在測試代碼裏面寫了個列表類型的使用代碼
1 ListOperations<String, Serializable> listOperation = redisTemplate.opsForList(); 2 IntStream.range(0, 100).forEach(i -> listOperation.leftPush("list", "item" + i));
向redis數據庫添加一個列表對象,key爲list,值爲item0~99,執行之後查看數據庫:
沒有問題,關於其他的集合、字典等操作,需要各位看官自行去實踐。
值得注意的是,以上的操作中向redis添加數據都是我們自己寫代碼來做的。在實際應用場景中,比如將redis作爲緩存的時候,可能代碼中有
很多地方都會涉及到向redis添加、更新、刪除數據,每個地方都自己寫代碼總是不太好的。因此Spring Cache整合了redis,基於註解的方式幫我們
簡化了這些操作,關於使用redis做緩存的部分下篇文章會講到。
本文到此結束,我是個小白,寫的文章可能深度與廣度都有所不足,同時也可能會有理解上的錯誤,望廣大網友不吝指教。
參考文章:
一起來學SpringBoot | 第九篇:整合Lettuce Redis
springboot系列文章之 集成redis 服務 (Lettuce & Jedis)