一、簡介
在使用SpringBoot搭建微服務的時候, 很多時候需要用Redis來快取一些資料 , 儲存一些高頻率訪問的資料。SpringBoot整合Redis所常用的Redis常用客戶端有三個:
- Jedis api
- redisson
- lettuce
本文采用lettuce來訪問Redis, 在Spring boot2之後, 對redis連線的支援, 預設就採用了lettuce
二、匯入依賴
<!-- SpringData 用於簡化資料庫訪問-->
<!--預設是lettuce客戶端-->
<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>
三、配置連線資訊
在application.yml
檔案中, 配置 Redis 連線資訊
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
lettuce:
pool:
max-active: 8 # 連線池最大連線數(使用負值表示沒有限制)
max-idle: 8 # 連線池中的最大空閒連線
min-idle: 0 # 連線池中的最小空閒連線
max-wait: 1000 # 連線池最大阻塞等待時間(使用負值表示沒有限制)
shutdown-timeout: 100 # 關閉超時時間
四、RedisConfig類介紹
快取配置類RedisConfig用於調優快取預設配置, 使RedisTemplate<String,Object>
的型別相容性更高
在redisTemplate()
這個方法中, 用Jackson2JsonRedisSerializer
更換掉了Redis預設的序列化方式 JdkSerializationRedisSerializer
spring-data-redis中序列化類有一下幾個:
GenericToStringSerializer
: 可以將任何物件泛化為字串並序列化Jackson2JsonRedisSerializer
: 序列化 Object 物件為 Json 字串 (與JacksonJsonRedisSerializer
相同)JdkSerializationRedisSerializer
: 序列化 Java 物件StringRedisSerializer
: 簡單的字串序列化
JdkSerializationRedisSerializer
序列化 : 被序列化物件必須實現Serializable
介面 , 被序列化除屬性內容還有其他內容 , 長度長且不易閱讀 , 預設就是採用這種序列化方式
儲存內容如下:
JdkSerializationRedisSerializer
序列化 : 被序列化物件不需要實現Serializable
介面 , 被序列化的結果清晰 , 內容易閱讀 , 且儲存位元組少 , 速度快
儲存內容如下:
StringRedisSerializer
序列化 : 一般如果key、value都是字串的話 , 用這個就可以了
五、編寫RedisConfig類
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定義快取key的生成策略,預設的生成策略是看不懂的(亂碼內容)
* 透過Spring的依賴注入特性進行自定義的配置注入並且此類是一個配置類, 可以更多程度的自定義配置
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(target.getClass().getName());
stringBuilder.append(method.getName());
for (Object obj :
params) {
stringBuilder.append(obj.toString());
}
return stringBuilder.toString();
}
};
}
/**
* 快取配置管理器
* @param factory
* @return
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory){
//以鎖寫入的方式建立RedisCacheWriter物件
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
//建立預設快取配置物件
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheManager cacheManager = new RedisCacheManager(writer,config);
return cacheManager;
}
//@ConditionalOnMissingBean(name="redisTemplate") 如果沒有RedisTemplate的Bean則使用該註解定義的Bean
@Bean
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory factory){
RedisTemplate<String,Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//在使用註解@Bean返回RedisTemplate的時候,同時配置hashKey與hashValue的序列化方式
//key採用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//value序列化方式採用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的key採用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//hash的value序列化方式採用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
五、使用RedisTemplate
(1)注入 RedisTemplate 物件
在要使用 Redis模板 的類中注入 RedisTemplate 物件
@Autowired
private RedisTemplate<String,Object> redisTemplate;
(2)使用 RedisTemplate 物件
redisTemplate 類是對lettuce的進一步封裝 , 因此他的方法並不與Redis語法一一對應。
對於Redis中所有型別共有的命令, 可以使用redisTemplate.方法()
對Redis進行操作
對於Redis中特定型別的命令, 需要使用redisTemplate.opsFor型別().方法()
對Redis進行操作
- String 型別 :
redisTemplate.opsForValue().方法()
- Hash 型別 :
redisTemplate.opsForHash().方法()
- List 型別 :
redisTemplate.opsForList().方法()
- Set 型別 :
redisTemplate.opsForSet().方法()
- ZSet 型別 :
redisTemplate.opsForZSet().方法()
(3) 使用 RedisTemplate 注入 ValueOperations
如果每次呼叫方法, 都用redisTemplate.opsFor型別().方法()
, 在程式碼中會有很多重複的redisTemplate.opsFor型別()
為了解決這個問題 , 我們可以使用 RedisTemplate 注入 型別 + Operations
以String型別為例:
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> vOps; // 相當於 vOps = redisTemplate.opsForValue()
RedisTemplate 型別和 ValueOperations 型別並沒有任何的關係, 他之所以可以注入是因為Spring在注入時對其進行了型別轉換。若想要深入瞭解redisTemplate如何注入到ValueOperations, 可以檢視此部落格: redisTemplate如何注入到ValueOperations
(4) 例項 - RedisTemplate 操作 String 型別
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> vOps;
public String gerString(String key){
String val = null;
if(redisTemplate.hasKey(key)){
val = (String) vOps.get(key);
log.info("從Redis查詢");
}else {
val ="模擬MySql查詢";
log.info("從MySql查詢");
vOps.set(key,val);
}
return val;
}
(5) 例項 - RedisTemplate 操作 Hash 型別
User實體類
@Data
public class User implements Serializable {
private String id;
private String name;
private Integer age;
}
查詢 User 方法
@Resource(name = "redisTemplate")
private HashOperations<String,String,User> hOps;
public User selectUserById(String id){
if(hOps.hasKey("user", id)){
log.info("查詢Redis");
return (User) hOps.get("user",id);
}else{
User user = new User();
user.setId(id);
user.setName("王五");
user.setAge(20);
log.info("查詢Mysql資料庫");
hOps.put("user",id,user);
return user;
}
}