1. 2022-03-12 SpringBoot 使用redis做緩存,設置失效時間以及序列化
SpringBoot的cache緩存,是針對返回值的一種操作
springboot使用redis做緩存時,默認只需要導入redis依賴,即可實現使用redis做緩存
不需要導入cache依賴
在啟動類上加上 @EnableCaching 即可開啟緩存功能
關於各個註解的使用,這里不再細說,網上詳細的教程很多,這里主要講一下如何指定過期時間
默認是永不過期,如果需要指定過期時間,則需要增加配置類
2. springboot 中 RedisCacheManager rm = new RedisCacheManager(redisTemplate);我的項目沒這個構造
pom.xml 引入redis 開啟緩存
<!-- cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.properties 配置文件
# Redis資料庫索引(默認為0)spring.redis.database=0
# Redis伺服器地址spring.redis.host=localhost
# Redis伺服器連接埠spring.redis.port=6379
# Redis伺服器連接密碼(默認為空)spring.redis.password=
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.pool.max-idle=8
# 連接池中的最小空閑連接
spring.redis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=0
添加cache的配置類
package www.ijava.com.configure;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Method;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//設置緩存過期時間
//rcm.setDefaultExpiration(60);//秒
return rcm;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
RedisService
package www.ijava.com.service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
/**
*/
@Service
public class RedisService {
@Autowired
private RedisTemplate redisTemplate;
/*
* //操作字元串
* redisTemplate.opsForValue();
//操作hash
redisTemplate.opsForHash();
//操作
redisTemplate.opsForList();
//操作
list redisTemplate.opsForSet();
//操作有序set
set redisTemplate.opsForZSet();
*/
/**
* 寫入緩存
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 寫入緩存設置時效時間
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量刪除對應的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量刪除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 刪除對應的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判斷緩存中是否有對應的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 讀取緩存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希獲取數據
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表獲取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合獲取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合獲取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
}
測試用的Controller
package www.ijava.com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import www.ijava.com.service.RedisService;
@RestController
public class DemoController {
@Autowired
private RedisService redisService ;
@RequestMapping(value = "/test")
public String demoTest(){
boolean result = redisService.set("1","value22222");
Object object = redisService.get("1");
Object name = redisService.get("name");
System.out.println(object);
return result+"-------"+object+" ---"+name;
}
}
使用Redis-cli客戶端查看
3. SpringBoot整合SpringSeesion實現Redis緩存
使用Spring Boot開發項目時我們經常需要存儲Session,因為Session中會存一些用戶信息或者登錄信息。傳統的web服務是將session存儲在內存中的,一旦服務掛了,session也就消失了,這時候我們就需要將session存儲起來,而Redis就是用來緩存seesion的一種非關系型資料庫,我們可以通過配置或者註解的方式將Spring Boot和Redis整合。而在分布式系統中又會涉及到session共享的問題,多個服務同時部署時session需要共享,Spring Session可以幫助我們實現這一功能。將Spring Session集成到Spring Boot框架中並使用Redis進行緩存是目前非常流行的解決方案,接下來就跟著我一起學習吧。
工具/材料
IntelliJ IDEA
首先我們創建一個Spring Boot 2.x的項目,在application.properties配置文件中添加Redis的配置,Spring和Redis的整合可以參考我其他的文章,此處不再詳解。我們設置服務埠server.port為8080埠用於啟動第一個服務。
接下來我們需要在pom文件中添加spring-boot-starter-data-redis和spring-session-data-redis這兩個依賴,spring-boot-starter-data-redis用於整合Spring Boot和Redis,spring-session-data-redis集成了spring-session和spring-data-redis,提供了session與redis的整合方案。
接下來我們創建一個配置類RedisSessionConfig,這個類使用@Configuration註解表明這是一個配置類。在這個類上我們同時添加註解@EnableRedisHttpSession,表示開啟Redis的Session管理。如果需要設置失效時間可以使用@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)表示一小時後失效。若同時需要設置Redis的命名空間則使用@EnableRedisHttpSession(maxInactiveIntervalInSeconds=3600, redisNamespace="{spring.session.redis.namespace}") ,其中{spring.session.redis.namespace}表示從配置文件中讀取這個命名空間。
配置完成後我們寫一個測試類SessionController,在這個類中我們寫兩個方法,一個方法用於往session中存數據,一個用於從session中取數據,代碼如下圖所示,我們存取請求的url。啟動類非常簡單,一般都是通用的,我們創建一個名為SpringbootApplication的啟動類,使用main方法啟動。
接下來我們使用Postman分別請求上面兩個介面,先請求存數據介面,再請求取數據介面,結果如下圖所示,我們可以看到數據已從redis中取出。另外需要注意sessionId的值,這是session共享的關鍵。
為了驗證兩個服務是否共享了session,我們修改項目的配置文件,將服務埠server.port改為8090,然後再啟動服務。此時我們不必在請求存數據的介面,只需要修改請求埠號再一次請求取數據的介面即可。由下圖可以看到兩次請求的sessionId值相同,實現了session的共享。
以上我們完成了SpringBoot整合SpringSeesion實現Redis緩存的功能,在此我們還要推薦一個Redis的可視化工具RedisDesktopManager,我們可以配置Redis資料庫的連接,然後便可以非常直觀地查看到存儲到Redis中的session了,如下圖所示,session的命名空間是share,正是從配置文件中讀取到的。
特別提示
如果Redis伺服器是很多項目共用的,非常建議配置命名空間,否則同時打開多個項目的瀏覽器頁面可能會導致session錯亂的現象。
4. 剛剛用spring boot 並用緩存資料庫redis ,哪裡有比較好的教程呢,菜鳥
首先可以在多台伺服器裝memcached,啟動時分別指定容量和埠
訪問時採用集群方式訪問,只需要spring配置文件裡面配置即可
value可以放任何對象,包括集合
每個鍵值的生命周期可以在放入時獨立設置
類庫可以用spymemcached
數據更新方式可以在後台的定時任務中執行
下面是spring mvc中配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
<property name="servers" value="伺服器A:埠,伺服器B:埠,伺服器C:埠" />
<property name="protocol" value="BINARY" />
<property name="transcoder">
<bean class="net.spy.memcached.transcoders.SerializingTranscoder">
<property name="compressionThreshold" value="1024" />
</bean>
</property>
<property name="opTimeout" value="2000" />
<property name="timeoutExceptionThreshold" value="1998" />
<property name="locatorType" value="CONSISTENT" />
<property name="hashAlg">
<value type="net.spy.memcached.DefaultHashAlgorithm">KETAMA_HASH</value>
</property>
<property name="failureMode" value="Redistribute" />
<property name="useNagleAlgorithm" value="false" />
</bean>
5. spring-boot-starter-data-redis 怎樣刪除緩存
使用手機自帶管理器打開c盤::cache文件夾是緩存目錄,建議大家定時清空。:所有temp文件夾
6. Spring boot + Mybatis plus + Redis實現二級緩存
1.1 通過application.yml配置redis的連接信息,springboot默認redis用的lecttuce客戶端,如果想用jedis的話,只需要在pom.xml中引入redis的時候排除在lecttuce,然後再導入jedis的jar包就好了,
1.2 打開mybatis plus的二級緩存,為true的時候是開啟的,false是關閉二級緩存
1.3 編寫緩存類繼承Cache類,實現Cache中的方法
1.4 早*.xml中加上<cache>標簽,type寫你所編寫二級緩存類的路徑
7. Redis的使用_springboot中redis的使用
Redis是一個nosql資料庫,可以存儲key-value值。因為其底層實現中,數據讀寫是基於內存,速度非常快,所以常用於緩存;進而因其衡蔽為獨立部署的中間件,常用於分布式緩存的實現方案。
常用場景有:緩存咐瞎州、秒殺控制、分布式鎖。
雖然其是基於內存讀寫,但底層也有持久化機神察制;同時具備集群模式;不用擔心其可用性。
關於Redis的使用,可以參考《Redis的使用方法、常見應用場景》
8. SpringBoot進階之緩存中間件Redis
大家好,一直以來我都本著 用最通俗的話理解核心的知識點, 我認為所有的難點都離不開 「基礎知識」 的鋪墊
「大佬可以繞過 ~」
本節給大家講講 「Java的SpringBoot框架」 , 之前我們學習的都是java的基礎知識和底層提供的一些能力,我們日常工作都是在寫介面。在我們在產品開發中,一般我們都會選擇比較穩定的框架來幫我們加速開發,不會自己去造輪子,而在java眾多框架中,spring框架表現的非常好,大部分公司都會首選它作為開發框架,而至今,大部分企業都是以 springboot 來構建項目了,一個穩健的系統需要引入穩定的技術~
如果你是一路看過來的,很高興你能夠耐心看完。前幾期都是帶大家學習了 SpringBoot 的基礎使用以及集成 mybatis 開發,這也是我們寫業務的基礎,如果你還不熟悉這些,請先看完它們。接下來的幾期內容將會帶大家進階使用,會先講解基礎 中間件 的使用和一些場景的應用,或許這些技術你聽說過,沒看過也沒關系,我會帶大家一步一步的入門,耐心看完你一定會有 收獲 ,本期將會給大家講解最熱門的緩存中間件技術 Redis ,同樣的,我們集成到 Springboot 中。最近github可能會被牆,所以我把源碼放到了國內gitee上,本節我們依然使用上期的代碼
Redis 是由義大利人Salvatore Sanfilippo(網名:antirez)開發的一款內存高速緩存資料庫。全稱叫 Remote Dictionary Server(遠程數據服務) 是由 C語言 編寫的,Redis是一個 key-value 存儲系統,它支持豐富的數據類型,如: string、list、set、zset(sorted set)、hash 。
它本質上是一種鍵值對資料庫,我們之前學習的 mysql 它是持久層的關系型資料庫,而 redis 它的存儲主要存在 內存 中。我們都知道在 內存 中的數據讀取是非常快的,就好比你把一個變數存到磁碟讀取和直接放到代碼中運行,肯定是在代碼中拿到的速度快,因為運行時期,都是直接存到內存的。
給大家總結一下:
有了基本的概念之後,我們下面進行環境搭建,在學習階段,安裝 redis 很簡單,生產環境一般我們也會選擇雲產品,一切為了服務保障,雖說它只是做緩存用,但也是系統的一把 保護傘
如果你是 mac 用戶,你可以運行如下命令:
安裝完成後會提示你運行命令,運行即可。
win 用戶也很簡單,直接下載 redis 軟體,雙擊運行即可,運行之後它會有一個小方塊的圖案,和 locahost:6379 的log,說明運行成功了。初始階段沒有配置的 redis 默認 host 就是本地, port 就是 6379 , 而且是 沒有密碼 就可以訪問的。
推薦一個客戶端軟體 Redis Desktop Manager ,它是 redis 的客戶端界面軟體,方便麵我們學習的時候 清理緩存 使用,生產慎連。
我們不給大家講它的基本命令使用,它也有語法,可以通過類似命令執行,如果想學習的小夥伴,可以自行搜索。本期重點內容是在 sprinboot 中的使用,我們平時開發不可能是去命令行里敲的,都是代碼里執行,而目前市面上有很多封裝好的庫,我們可以直接調用它的方法,很方便的就可以操作它了,不用記一些繁瑣的命令,下面我們就實際操作一下:
修改 pom.xml
修改 application.yml :
redis 默認是有 16 個庫,不是 15 個啊,從 0 開始算的,我們隨便連一個
通過代碼很好理解, 首先需要引入 StringRedisTemplate ,然後需要設置一個 key ,那麼思考一下,這個 key 允許重復嗎
我們進客戶端看一下,發現 key 還是只有一個,但是值變成了新的值了,所以可以得知 key 是唯一的,我們重新設置的時候相當於刷新了它。
在 redis 中刪除緩存有兩種方式,一種是自我消亡,也就是 過期 銷毀,還有有一種是 主動 銷毀,我們先看一下,過期時間如何設置
我們設置了 10s 後過期,過完10s後發現,這個```key data``消失了。我們在看看如何主動刪除
我們可以利用 Redis 做一個計數器,實現自增功能,你可以用它做網站訪問統計
通常做法,我們會把它封裝一下,後續使用直接引入封裝好的即可,把它直接交給 Springboot容器 管理
其實這個類,你還可以繼續進一步封裝,比如約束 key 的規范,約束過期時間,約束數據類型等等,這一切也都是為了規范和後期維護,防止濫用緩存
緩存的主要場景是用於解決熱點數據問題,因為這些數據是訪問頻率比較高的,當大量的請求進來, mysql 可能壓力很大,這樣一來,數據查詢效率就很慢,用戶肯不高興等了,這樣用戶體驗很不好。所以我們一般做法,都是把這些熱點數據放到緩存里,因為緩存讀取速度很快。當有新數據的時候,我們再及時更新它,一般流程是先查詢緩存,查到了直接返回緩存數據,查不到再走資料庫,然後再刷回緩存。
但是並發足夠大的時候,還是會暴露出很多問題,比如面試常問的一些高頻問題 緩存雪崩、緩存穿透、緩存雪崩 ,這些問題後邊會給大家專門講,和如何去防範。所以總的來說,引入任何一門技術並不是萬事大吉,還需我們不斷的在實踐中積累經驗
本期到這里就結束了,總結一下,我們了解了什麼是 redis ,以及在 springboot 中如何去使用它們,很簡單,沒什麼復雜的東西。但這里想多說一點的是,緩存的設計卻是很復雜的,因為工具是死的,人是活的,我們如何正確設計,需要我們在項目中不斷的積累。
我們之前教大家查詢列表數據,都是所有數據返回,還沒有教大家如何去做分頁,下期將帶大家學習一下 mybatis 分頁插件的使用 ,下期不見不散, 關注我,不迷路~