cachehelper java_spring boot:使用spring cache+caffeine做进程内缓存(本地缓存)(spring boot 2.3.1)...

一,为什么要使用caffeine做本地缓存?

1,spring boot默认集成的进程内缓存在1.x时代是guava cache

在2.x时代更新成了caffeine,

功能上差别不大,但后者在性能上更胜一筹,

使用caffeine做本地缓存,取数据可以达到微秒的级别,

一次取数据用时经常不足1毫秒,

这样可以及时响应请求,在高并发的情况下把请求拦截在上游,

避免把压力带到数据库,

所以我们在应用中集成它对于系统的性能有极大的提升

2,与之相比,即使是本地的redis,

响应时间也比进程内缓存用时要更久,

而且在应用服务器很少有专门配备redis缓存的做法,

而是使用专门的redis集群做为分布式缓存

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,演示项目的相关信息

1,项目地址:

https://github.com/liuhongdi/caffeine

2,项目原理:

我们建立了两个cache:goods,goodslist

分别用来缓存单个商品详情和商品列表

3,项目结构:

如图:

4d5fad6eef2b5c5c3ec6a9ad4f9c94dd.png

三,配置文件说明

1,pom.xml

org.springframework.boot

spring-boot-starter-cache

com.github.ben-manes.caffeine

caffeine

2.8.5

2,application.properties

#profile

spring.profiles.active=cacheable

这个值用来配置cache是否生效

我们在测试或调试时有时会用关闭缓存的需求

如果想关闭cache,把这个值改变一下即可

3,mysql的数据表结构:

CREATE TABLE `goods` (

`goodsId`int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',

`goodsName` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'name',

`subject` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',

`price`decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '价格',

`stock`int(11) NOT NULL DEFAULT '0' COMMENT 'stock',

PRIMARY KEY (`goodsId`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表'

四,java代码说明

1,CacheConfig.java

@Profile("cacheable") //这个当profile值为cacheable时缓存才生效

@Configuration

@EnableCaching//开启缓存

public classCacheConfig {public static final int DEFAULT_MAXSIZE = 10000;public static final int DEFAULT_TTL = 600;private SimpleCacheManager cacheManager = newSimpleCacheManager();//定义cache名称、超时时长(秒)、最大容量

public enumCacheEnum{

goods(600,3000), //有效期600秒 , 最大容量3000

goodslist(600,1000), //有效期600秒 , 最大容量1000

;

CacheEnum(int ttl, intmaxSize) {this.ttl =ttl;this.maxSize =maxSize;

}private int maxSize=DEFAULT_MAXSIZE; //最大數量

private int ttl=DEFAULT_TTL; //过期时间(秒)

public intgetMaxSize() {returnmaxSize;

}public intgetTtl() {returnttl;

}

}//创建基于Caffeine的Cache Manager

@Bean

@PrimarypublicCacheManager caffeineCacheManager() {

ArrayList caches = new ArrayList();for(CacheEnum c : CacheEnum.values()){

caches.add(newCaffeineCache(c.name(),

Caffeine.newBuilder().recordStats()

.expireAfterWrite(c.getTtl(), TimeUnit.SECONDS)

.maximumSize(c.getMaxSize()).build())

);

}

cacheManager.setCaches(caches);returncacheManager;

}

@BeanpublicCacheManager getCacheManager() {returncacheManager;

}

}

说明:根据CacheEnum这个enum的内容来生成Caffeine Cache,并保存到cachemanager中

如果需要新增缓存,保存到CacheEnum中

@Profile("cacheable"): 当spring.profiles.active的值中包括cacheable时cache才起作用,不包含此值时则cache被关闭不生效

@EnableCaching :  用来开启缓存

recordStats:记录统计数据

expireAfterWrite:在写入到达一定时间后过期

maximumSize:指定最大容量

2,GoodsServiceImpl.java

@Servicepublic class GoodsServiceImpl implementsGoodsService {

@ResourceprivateGoodsMapper goodsMapper;//得到一件商品的信息

@Cacheable(value = "goods", key="#goodsId",sync = true)

@OverridepublicGoods getOneGoodsById(Long goodsId) {

System.out.println("query database");

Goods goodsOne=goodsMapper.selectOneGoods(goodsId);returngoodsOne;

}//获取商品列表,只更新缓存

@CachePut(value = "goodslist", key="#currentPage")

@Overridepublic Map putAllGoodsByPage(intcurrentPage) {

Map res =getAllGoodsByPageDdata(currentPage);returnres;

}//获取商品列表,加缓存//@Cacheable(key = "#page+'-'+#pageSize") 多个参数可以用字符串连接起来

@Cacheable(value = "goodslist", key="#currentPage",sync = true)

@Overridepublic Map getAllGoodsByPage(intcurrentPage) {

Map res =getAllGoodsByPageDdata(currentPage);returnres;

}//从数据库获取商品列表

public Map getAllGoodsByPageDdata(intcurrentPage) {

System.out.println("-----从数据库得到数据");

Map res = new HashMap();

PageHelper.startPage(currentPage,5);

List goodsList =goodsMapper.selectAllGoods();

res.put("goodslist",goodsList);

PageInfo pageInfo = new PageInfo<>(goodsList);

res.put("pageInfo",pageInfo);returnres;

}

}

说明:

@Cacheable(value = "goodslist", key="#currentPage",sync = true):

当缓存中存在数据时,则直接从缓存中返回,

如果缓存中不存在数据,则要执行方法返回数据后并把数据保存到缓存.

@CachePut(value = "goodslist", key="#currentPage"):

不判断缓存中是否存在数据,只更新缓存

3,HomeController.java

//商品列表 参数:第几页

@GetMapping("/goodslist")publicString goodsList(Model model,

@RequestParam(value="p",required = false,defaultValue = "1") intcurrentPage) {

Map res =goodsService.getAllGoodsByPage(currentPage);

model.addAttribute("pageInfo", res.get("pageInfo"));

model.addAttribute("goodslist", res.get("goodslist"));return "goods/goodslist";

}//更新

@ResponseBody

@GetMapping("/goodslistput")public String goodsListPut(@RequestParam(value="p",required = false,defaultValue = "1") intcurrentPage) {

Map res =goodsService.putAllGoodsByPage(currentPage);return "cache put succ";

}//清除

@CacheEvict(value="goodslist", allEntries=true)

@ResponseBody

@GetMapping("/goodslistevict")publicString goodsListEvict() {return "cache evict succ";

}

说明:

@CacheEvict(value="goodslist", allEntries=true):用来清除goodslist中的缓存

4,StatsController.java

@Profile("cacheable")

@Controller

@RequestMapping("/stats")public classStatsController {//统计,如果是生产环境,需要加密才允许访问

@ResourceprivateCacheManager cacheManager;

@GetMapping("/stats")

@ResponseBodypublicString stats() {

CaffeineCache caffeine= (CaffeineCache)cacheManager.getCache("goodslist");

Cache goods=caffeine.getNativeCache();

String statsInfo="cache名字:goodslist
";

Long size=goods.estimatedSize();

statsInfo+= "size:"+size+"
";

ConcurrentMap map=goods.asMap();

statsInfo+= "map keys:
";for(Object key : map.keySet()) {

statsInfo+= "key:"+key.toString()+";value:"+map.get(key)+"
";

}

statsInfo+= "统计信息:"+goods.stats().toString();returnstatsInfo;

}

}

五,效果测试

1,访问地址:

http://127.0.0.1:8080/home/goodslist/?p=1

如图:

36685f9219b8f4de176cd4529838d3cd.png

刷新几次后,可以看到,在使用cache时:

costtime aop 方法doafterreturning:毫秒数:0

使用的时间不足1毫秒

2,查看统计信息,访问:

http://127.0.0.1:8080/stats/stats

如图:

eff36053af15a5cca12795797d4df697.png

3,清除cache信息:

http://127.0.0.1:8080/home/goodslistevict

查看缓存的统计:

cache名字:goodslist

size:0map keys:

统计信息:CacheStats{hitCount=1, missCount=3, loadSuccessCount=3, loadFailureCount=0, totalLoadTime=596345574, evictionCount=0, evictionWeight=0}

可以看到数据已被清空

六,查看spring boot的版本

. ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | '_ |'_| | '_ \/ _` | \ \ \ \

\\/ ___)| |_)| | | | | || (_| |) ) ) )'|____| .__|_| |_|_| |_\__, | / / / /

=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v2.3.1.RELEASE)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值