之前用SpringBoot+MyBatisPlus+SpringMVC整合搭建了一個基礎(chǔ)web開發(fā)框架恳蹲,使用這三個框架搭建出來項目結(jié)構(gòu)非常的清爽查辩,沒有過多的配置文件骏全,各個模塊之間有清晰的聯(lián)系与斤,非常適合敏捷開發(fā)肪康。
最近學(xué)習(xí)了Redis這個基于內(nèi)存的,Key-Value數(shù)據(jù)形式的高性能數(shù)據(jù)庫撩穿,感覺學(xué)習(xí)了入門之后很簡單磷支,沒有體會到它具體能干嘛,我就想著使用Redis這個數(shù)據(jù)庫來整合之前搭建的框架食寡,利用Spring中的緩存機制雾狈,將查詢的信息緩存到Redis中。
抵皱、善榛、、呻畸、移盆、、擂错、味滞、、钮呀、剑鞍、、
個人博客地址:http://z77z.oschina.io/
爽醋,蚁署,,蚂四,光戈,,遂赠,久妆,,跷睦,筷弦,,
安裝Redis
Window 下安裝 下載地址:https://github.com/MSOpenTech/redis/releases。 Redis 支持32 位和64 位烂琴。這個需要根據(jù)你系統(tǒng)平臺的實際情況選擇爹殊,這里我們下載 Redis-x64-xxx.zip壓縮包到 C盤的tools目錄中,解壓后奸绷,將文件夾重新命名為 redis梗夸。
打開一個 cmd 窗口 使用cd命令切換目錄到 C:\tools\redis 運行 redis-server.exe redis.windows.conf 。
如果想方便的話号醉,可以把 redis 的路徑加到系統(tǒng)的環(huán)境變量里反症,這樣就省得再輸路徑了,后面的那個 redis.windows.conf 可以省略扣癣,如果省略惰帽,會啟用默認的。輸入之后父虑,會顯示如下界面:
啟動成功后不要關(guān)閉命令窗口该酗,不然redis服務(wù)也會關(guān)閉。如果不想每次使用都一直開著這個命令窗口士嚎,可以將redis服務(wù)添加到windows的服務(wù)中:
安裝命令:
redis-server.exe --service-install redis.windows.conf --loglevel verbose
卸載命令:
redis-server --service-uninstall
安裝成功后呜魄,可以在windows的服務(wù)管理中對redis進行管理,就不用每次都打開命令窗口來啟動redis服務(wù)了莱衩,如下圖:
獲取之前項目
環(huán)境我就直接在之前的整合框架上進行搭建爵嗅,之前項目下載地址:https://git.oschina.net/z77z/springboot_mybatisplus
注意:之前搭建這個框架的時候我為了獲取基礎(chǔ)數(shù)據(jù),在啟動springboot的時候也啟動了爬蟲程序笨蚁,如果不想每次啟動都啟動爬蟲可以注釋掉啟動類中的run方法睹晒。
添加Redis依賴到pom.xml中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
在application.properties中添加配置
# REDIS (RedisProperties)
# Redis數(shù)據(jù)庫索引(默認為0)
spring.redis.database=0
# Redis服務(wù)器地址
spring.redis.host=localhost
# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負值表示沒有限制)
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
我們需要做的配置到這里就已經(jīng)完成了,Spring Boot會在偵測到存在Redis的依賴并且Redis的配置是可用的情況下括细,使用RedisCacheManager初始化CacheManager伪很。也就是說要使用緩存的話,SpringBoot就會選擇Redis來作為緩存的容器奋单。
編寫一個簡單的redis讀寫測試列
/**
* redis讀寫測試
* @author z77z
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void redisTest() throws Exception {
//保存字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
//讀取字符串
String aaa = stringRedisTemplate.opsForValue().get("aaa");
System.out.println(aaa);
}
}
打印結(jié)果:
編寫緩存測試列
不使用緩存:
/**
* 獲取數(shù)據(jù)锉试,并且做緩存處理
* @author z77z
*
*/
@Component
public class RedisCache {
@Autowired
BeautifulPicturesService beautifulPicturesService;
//@Cacheable(value = "BeautifulPictures")
public BeautifulPictures getBeautifulPicturesList(String id) {
return beautifulPicturesService.selectById(id);
}
}
/**
* 測試類
* @author z77z
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
@Autowired
BeautifulPicturesService beautifulPicturesService;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisCache redisCache;
@Test
public void redisTest() throws Exception {
//保存字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
//讀取字符串
String aaa = stringRedisTemplate.opsForValue().get("aaa");
System.out.println(aaa);
}
@Test
public void CacheTest() {
BeautifulPictures beautifulPicture = redisCache.getBeautifulPicturesList("1011");
System.out.println("第一次查詢結(jié)果:");
System.out.println(beautifulPicture);
BeautifulPictures beautifulPicture1 = redisCache.getBeautifulPicturesList("1011");
System.out.println("第二次查詢結(jié)果:");
System.out.println(beautifulPicture1);
}
}
執(zhí)行結(jié)果:
可以從日志中看出兩次查詢都是執(zhí)行了sql,也就是執(zhí)行了
getBeautifulPicturesList
這個方法
使用緩存:
在getBeautifulPicturesList方法的上面添加@Cacheable(value = "BeautifulPictures")注解览濒,當(dāng)請求這個方法時會先判斷緩存中是否存在呆盖,存在就在緩存中獲取,不會執(zhí)行這個方法贷笛。不存在就正常執(zhí)行這個方法獲取返回值并且存如緩存中应又。添加注解后執(zhí)行結(jié)果如下:
從日志中可以看出,第一次查詢的時候執(zhí)行的sql乏苦,而第二次查詢的時候沒有執(zhí)行sql丁频,說明是從緩存中獲取的數(shù)據(jù)。
緩存數(shù)據(jù)一致性保證
CRUD (Create 創(chuàng)建,Retrieve 讀取席里,Update 更新,Delete 刪除) 操作中拢驾,除了 R具備冪等性奖磁,其他三個發(fā)生的時候都可能會造成緩存結(jié)果和數(shù)據(jù)庫不一致。為了保證緩存數(shù)據(jù)的一致性繁疤,在進行 CUD 操作的時候我們需要對可能影響到的緩存進行更新或者清除咖为。如下:
/**
* 獲取數(shù)據(jù),并且做緩存處理
* @author z77z
*
*/
@Component
public class RedisCache {
@Autowired
BeautifulPicturesService beautifulPicturesService;
//查詢
@Cacheable(value = "beautifulPictures")
public BeautifulPictures getBeautifulPicturesList(String id) {
return beautifulPicturesService.selectById(id);
}
//修改
@CachePut(value = "beautifulPictures")
public void updateBeautifulPicture(String id) {
BeautifulPictures beautifulPictures = new BeautifulPictures();
beautifulPictures.setTitle("Title被我修改了一下稠腊,哈哈");
beautifulPictures.setId(id);
beautifulPicturesService.updateById(beautifulPictures);
}
}
/**
* 測試類
* @author z77z
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
@Autowired
BeautifulPicturesService beautifulPicturesService;
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisCache redisCache;
@Test
public void redisTest() throws Exception {
//保存字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
//讀取字符串
String aaa = stringRedisTemplate.opsForValue().get("aaa");
System.out.println(aaa);
}
@Test
public void CacheTest() {
String id = "1";
BeautifulPictures beautifulPicture = redisCache.getBeautifulPicturesList(id);
System.out.println("第一次查詢結(jié)果:");
System.out.println(beautifulPicture);
BeautifulPictures beautifulPicture1 = redisCache.getBeautifulPicturesList(id);
System.out.println("第二次查詢結(jié)果:");
System.out.println(beautifulPicture1);
redisCache.updateBeautifulPicture(id);
BeautifulPictures beautifulPicture2 = redisCache.getBeautifulPicturesList(id);
System.out.println("第三次查詢結(jié)果:");
System.out.println(beautifulPicture2);
}
}
保持緩存一致性測試結(jié)果:
在會導(dǎo)致數(shù)據(jù)發(fā)生改變的方法上添加
@CachePut(value = "beautifulPictures")
注解躁染,添加后會更新緩存中的值,并且每次都會正常執(zhí)行方法內(nèi)容架忌。
SpringBoot緩存注解詳解
- @Cacheable:作用是主要針對方法配置吞彤,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存
主要參數(shù)說明:
value
:緩存的名稱,在 spring 配置文件中定義叹放,必須指定至少一個饰恕,例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}。key
:緩存的 key井仰,可以為空埋嵌,如果指定要按照 SpEL 表達式編寫,如果不指定俱恶,則缺省按照方法的所有參數(shù)進行組合雹嗦,例如:@Cacheable(value=”testcache”,key=”#userName”)。condition
:緩存的條件合是,可以為空了罪,使用 SpEL 編寫,返回 true 或者 false端仰,只有為 true 才進行緩存捶惜,例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2。
- @CachePut:作用是主要針對方法配置荔烧,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存吱七,和 @Cacheable 不同的是,它每次都會觸發(fā)真實方法的調(diào)用
主要參數(shù)說明:
value
鹤竭,key
和condition
參數(shù)配置和@Cacheable一樣踊餐。
- @CacheEvict:作用是主要針對方法配置,能夠根據(jù)一定的條件對緩存進行清空
主要參數(shù)說明:
value
臀稚,key
和condition
參數(shù)配置和@Cacheable一樣吝岭。allEntries
:是否清空所有緩存內(nèi)容,缺省為 false,如果指定為 true窜管,則方法調(diào)用后將立即清空所有緩存散劫,例如:@CachEvict(value=”testcache”,allEntries=true)。beforeInvocation
:是否在方法執(zhí)行前就清空幕帆,缺省為 false获搏,如果指定為 true,則在方法還沒有執(zhí)行的時候就清空緩存失乾,缺省情況下常熙,如果方法執(zhí)行拋出異常,則不會清空緩存碱茁,例如@CachEvict(value=”testcache”裸卫,beforeInvocation=true)。
另外說下: @cache(“something");這個相當(dāng)于save()操作纽竣,@cachePut相當(dāng)于Update()操作墓贿,只要他標示的方法被調(diào)用,那么都會緩存起來退个,而@cache則是先看下有沒已經(jīng)緩存了募壕,然后再選擇是否執(zhí)行方法。@CacheEvict相當(dāng)于Delete()操作语盈。用來清除緩存用的舱馅。