創建SpringBoot項目:https://blog.csdn.net/weixin_41381863/article/details/106504682
引入相關依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 這裏會根據引入的springboot版本自動選擇,也可單獨指定版本 -->
<!-- 最新版本查詢:https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<!-- <version>2.3.0.RELEASE</version> -->
</dependency>
<!-- 如果需要配置連接池,還需要以下依賴。不使用連接池則不需要 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置屬性
### redis配置 ###
spring.redis.host=127.0.0.1
spring.redis.port=6379
# 安裝的時候如果沒有設置密碼則沒有此項
spring.redis.password=123456
# 使用redis的哪一個庫,默認是0
spring.redis.database=0
# redis連接超時時間 單位毫秒
spring.redis.timeout=2000
# 連接池最大連接數(負值表示沒有限制,比如-1)
spring.redis.lettuce.pool.max-active=20
# 獲取連接最大阻塞等待時間(負值表示沒有限制,比如-1)
spring.redis.lettuce.pool.max-wait=-1
# 連接池中的最小空閒連接
spring.redis.lettuce.pool.min-idle=20
# 連接池中的最大空閒連接
spring.redis.lettuce.pool.max-idle=100
# springboot默認使用的redis連接是lettuce。
# 如果需要換成jedis需要額外引入jedis的依賴包。
# 並且使用下面的配置
#spring.redis.jedis.pool.max-active=
### redis配置 ###
如果需要使用jedis,則加入以下的依賴包(最好是在spring-boot-starter-data-redis中將lettuce的依賴排除)。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<!-- 最新版本查詢:https://mvnrepository.com/artifact/redis.clients/jedis/3.3.0 -->
<version>3.3.0</version>
</dependency>
使用RedisTemplate操作redis
RedisTemplate是springboot-redis提供的一個操作redis的模板,它一個泛型類RedisTemplate<K, V>。注意,它是被默認裝配進Spring的IoC的,即我們可以直接使用@Autowired或@Resource使用它。除此之外,還提供了一個StringRedisTemplate來操作redis,同樣的,StringRedisTemplate也是被默認裝配進IoC的。這就是爲什麼,很多書籍或博客寫了配置RedisTemplate,而直接使用了StringRedisTemplate。其中,StringRedisTemplate繼承RedisTemplate<String, String>。按道理講,裝配了父類,卻直接注入子類,肯定是會報錯的(不知道你是否有思考過這個問題^_^)。這麼一來,如果只使用StringRedisTemplate,其實配置或者不配置RedisTemplate<K, V>都沒什麼實際意義。
接下來,慢慢道來爲什麼要配置RedisTemplate,以及StringRedisTemplate和RedisTemplate關係。
注意一:假如我們不配置RedisTemplate,而直接使用RedisTemplate。會導致我們存入redis的數據變成以下形式。
key:
value:
而直接使用StringRedisTemplate,又不會出現這種情況。
RedisTemplate使用的默認使用的序列化是JdkSerializationRedisSerializer<T>。StringRedisTemplate繼承了RedisTemplate,但是,在StringRedisTemplate的構造方法中,重新設置了序列化方式爲StringRedisSerializer。如下:
其中RedisSerializer.string()追蹤進去就是
除此之外,還支持很多序列化方式。所有的序列化方式必須實現RedisSerializer<T>接口。如下所示。其中,支持我們自定義序列化方式,還可以使用fastjson中的序列化方式。
注意二:在使用RedisTemplate<K, V>時。獲取RedisTemplate的bean時,其實是根據bean的名稱去找的(默認裝配的是一個泛型的bean)。所以是沒辦法按照類型去獲取bean的。
正確的的代碼:
@Autowired
private RedisTemplate<String, Object> redisTemplate;
錯誤的代碼:
@Autowired
private RedisTemplate<String, Object> redisTemplateObj;
關於使用RedisTemplate還是StringRedisTemplate。我是這麼認爲的,畢竟redis除了支持string還支持hash等其他數據類型。如果團隊要求,在存儲對象時,在代碼中先將其序列化爲json數據之後再進行存儲,那麼直接使用StringRedisTemplate即可。如果需要直接使用hash類型,且對象中帶有非Stirng類型的屬性,假如使用StringRedisTemplate,會出現類型轉換異常ClassCastException。通過上面的分析,StringRedisTemplate就是一個將序列化方式更改爲StringRedisSerializer的RedisTemplate。那麼,就需要老老實實的使用RedisTemplate。綜上,還是統一使用RedisTemplate比較好,操作類型比較豐富。
使用RedisTemplate時,爲了規避上述問題,就需要重新裝配RedisTemplate。
因爲序列化使用了FastJson。所以還需要引入FastJson的依賴包。
注意:一旦設置了序列化方式,不要萬不得已,不要更改。比如,存儲數據用了A序列化方式,獲取數據如果採用B序列化方式,會出現異常,導致獲取數據失敗。那麼,需要更改序列化方式,則需要清除redis全部數據。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<!-- 最新版本查詢:https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<version>1.2.70</version>
</dependency>
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> initRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 支持事物
redisTemplate.setEnableTransactionSupport(true);
// key的序列化方式採用StringRedisSerializer。相信很少用對象作爲key的吧。
// 如果要走非主流路線,將對象作爲key,且對象含有非String屬性,需要將key的序列化方式
// 更改爲下面的value序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// 設置value的序列化方式GenericFastJsonRedisSerializer(需要依賴fastjson)
GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
// 如果不想使用fastJson。常用的還有jackson的序列化方式。springboot項目中,默認帶了jackson。
// Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
// ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jacksonSerializer.setObjectMapper(objectMapper);
// redisTemplate.setValueSerializer(jacksonSerializer);
// redisTemplate.setHashValueSerializer(jacksonSerializer);
// 顧名思義,在屬性設置之後運行.初始化配置的作用
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
因爲這裏,我們重新裝配了RedisTemplate<String, Object>,指定了泛型。所以在注入RedisTemplate<String, Object>時,就可以按類型獲取了(獲取bean的時候,可以任意命名)。
至此,就完成了所有配置。然後可以愉快的玩耍了。
測試用例:
@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheTest {
// @Autowired
// private StringRedisTemplate redisTemplate;
@Autowired
private RedisTemplate<String, Object> redisTemplateObj;
@Test
public void setStringTest() {
redisTemplateObj.opsForValue().set("k1", "zepal");
System.out.println("done");
}
@Test
public void getStringTest() {
String result = (String) redisTemplateObj.opsForValue().get("k1");
System.out.println(result);
}
@Test
public void setHashObjTest() {
Map<String, Object> map = new HashMap<>();
map.put("name", "zepal");
map.put("gender", "男");
map.put("age", 18);
redisTemplateObj.opsForHash().putAll("h1", map);
System.out.println("done");
}
@Test
public void getHashObjTest() {
String name = (String) redisTemplateObj.opsForHash().get("h1", "name");
System.out.println(name);
}
}
操作封裝
在開發中,如果每次操作RedisTemplate都需要調用它的api,比較麻煩,所以,可以簡單進行封裝一下。
@Service
public class CacheService {
private RedisTemplate<String, Object> redisTemplate;
/**
* <p>新增緩存:不帶超時策略
* */
public void setCache(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* <p>新增緩存:帶超時策略
* */
public void setCache(String key, String value,
long timeOut, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeOut, timeUnit);
}
/**
* <p>獲取緩存
* */
public String getCache(String key) {
String value = (String) redisTemplate.opsForValue().get(key);
return value;
}
/**
* <p>刪除緩存
* */
public boolean deleteCache(String key) {
Boolean isSuccess = redisTemplate.delete(key);
return isSuccess;
}
// 還可以擴展其它...
}