当前位置: 首页 > news >正文

申请个人网站怎么申请潍坊关键词优化软件

申请个人网站怎么申请,潍坊关键词优化软件,seo比较好的优化,弹幕网站如何做hello,伙伴们好久不见,我是shigen。发现有两周没有更新我的文章了。也是因为最近比较忙,基本是993了。 缓存大家再熟悉不过了,几乎是现在任何系统的标配,并引申出来很多的问题:缓存穿透、缓存击穿、缓存雪崩…

hello,伙伴们好久不见,我是shigen。发现有两周没有更新我的文章了。也是因为最近比较忙,基本是993了。

缓存大家再熟悉不过了,几乎是现在任何系统的标配,并引申出来很多的问题:缓存穿透、缓存击穿、缓存雪崩…哎,作为天天敲业务代码的人,哪有时间天天考虑这么多的破事。直接封装一个东西,我们直接拿来就用岂不是美哉。看了项目组的代码,我也忍不住 diy 了,对于增删就算了,就是 get set 的 API 调用,修改?直接删了重新添加吧,哪有先查缓存再去修改保存的。难点就在于缓存的查询,要不缓存的穿透、击穿、雪崩会诞生对吧。
我们先看下缓存的逻辑:

是的,其实就是这么简单,剩下的就是考虑一下缓存穿透问题,最常见的处理方式就是加锁。这里我采用的是信号量 Semaphore。
好的,现在展示我的代码,代码结构如下:

.
├── CacheEnum.java									-- 缓存枚举
├── CacheLoader.java								-- 缓存加载接口
├── CacheService.java								-- 缓存服务
└── CacheServiceImpl.java 					-- 缓存服务实现类1 directory, 4 files

ok,现在我们一一讲解下:

CacheEnum

主要的代码:

public enum CacheEnum {/** 用户token缓存 */USER_TOKEN("USER_TOKEN", 60, "用户token"),/** 用户信息缓存 */USER_INFO("USER_INFO", 60, "用户信息"),;/** 缓存前缀 */private final String  cacheName;/** 缓存过期时间 */private final Integer expire;/** 缓存描述 */private final String  desc;

其他的就是 get/set 方法,这里不做展示。主要解决的痛点就是缓存过期时间的统一管理、缓存名称的统一管理。

CacheService

这里边就是定义了缓存操作的接口:

public interface CacheService {/*** 获取缓存* @param cacheName 缓存名称* @param key 缓存key* @param type 缓存类型* @return 缓存值* @param <T> 缓存类型*/<T> T get(String cacheName, String key, Class<T> type);/*** 获取缓存* @param cacheName 缓存名称* @param key 缓存key* @param type 缓存类型* @param loader 缓存加载器* @return 缓存值* @param <T> 缓存类型*/<T> T get(String cacheName, String key, Class<T> type, CacheLoader<T> loader);/*** 删除缓存* @param cacheName 缓存名称* @param key 缓存key*/void delete(String cacheName, String key);/*** 设置缓存* @param cacheName 缓存名称* @param key 缓存key* @param value 缓存值*/void set(String cacheName, String key, Object value);
}    

其实就是一些增删查的方法。只不过这里我们更加关注的是:缓存的名称,缓存的 key,缓存对象,缓存对象的类型。
在 22 行这里用到了CacheLoader 接口,其实就是处理缓存对象在缓存中拿不到的问题,它的定义也很简单:

@FunctionalInterface
public interface CacheLoader<V> {/*** 加载缓存* @param key 缓存key* @return 缓存值*/V load(String key);
}

就一个方法,直接使用上 lambda 表达式,下边的测试类会讲到。

CacheServiceImpl

@Slf4j
@Service
public class CacheServiceImpl implements CacheService {/** Semaphore */private static final Semaphore        CACHE_LOCK = new Semaphore(100);/** 缓存操作 */@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 获取缓存key* @param cacheName 缓存名称* @param key 缓存key* @return 缓存key*/private String getCacheKey(String cacheName, String key) {Assert.isTrue(StrUtil.isNotBlank(cacheName), "cacheName不能为空");Assert.isTrue(StrUtil.isNotBlank(key), "key不能为空");Assert.isTrue(CacheEnum.getByCacheName(cacheName) != null, "需要使用CacheEnum枚举创建缓存");return cacheName + ":" + key;}@Overridepublic <T> T get(String cacheName, String key, Class<T> type) {Object value = redisTemplate.opsForValue().get(getCacheKey(cacheName, key));if (value != null) {return type.cast(value);}return null;}@Overridepublic <T> T get(String cacheName, String key, Class<T> type, CacheLoader<T> cacheLoader) {try {// 获取锁, 防止缓存击穿CACHE_LOCK.acquire();String cacheKey = getCacheKey(cacheName, key);Object value = redisTemplate.opsForValue().get(cacheKey);if (value != null) {return type.cast(value);}value = cacheLoader.load(cacheKey);if (value != null) {this.set(cacheName, key, value);return type.cast(value);}} catch (InterruptedException e) {log.warn("获取锁失败");} finally {CACHE_LOCK.release();}return null;}@Overridepublic void delete(String cacheName, String key) {redisTemplate.opsForValue().getOperations().delete(getCacheKey(cacheName, key));}@Overridepublic void set(String cacheName, String key, Object value) {String cacheKey = getCacheKey(cacheName, key);CacheEnum cacheEnum = CacheEnum.getByCacheName(cacheName);Assert.isTrue(cacheEnum != null, "需要使用CacheEnum枚举创建缓存");redisTemplate.opsForValue().set(cacheKey, value, cacheEnum.getExpire(), TimeUnit.SECONDS);}
}

这里就是接口的具体实现。需要注意:

  1. 在获得完整的缓存 key 的时候,我们其实对于缓存的 cacheName 做了验证,参见上代码块 21 行,不允许自己定义缓存的 cacheName,统一在枚举类中定义。
  2. 因为 tair 的资源有点不好申请,这里使用的 redis 作为缓存的工具,结合 spring-boot-starter-data-redis 作为操作的 API。
  3. 应对缓存穿透问题,这里使用的是Semaphore 信号量。

别的就没什么好说的,现在我们来测试一下我们的封装是否管用。

测试代码

设置缓存

测试用定义的枚举类创建缓存:

    @Testvoid set() {cacheService.set(CacheEnum.USER_INFO.getCacheName(), "10001", getFakeUser("10001"));}

是没问题的,不用枚举类创建:

    @Testvoid testSetSelfDefinedCacheName() {cacheService.set("user", "10001", getFakeUser("10001"));}

直接异常出来了:

java.lang.IllegalArgumentException: 需要使用CacheEnum枚举创建缓存
读取缓存

读取缓存,我的 API 中分为两种情况:直接读取,没有就算了;读取缓存,没有的话再从 DB 中拿。对应的单测如下:

    @Testvoid testGet() {UserEntity user = cacheService.get(CacheEnum.USER_INFO.getCacheName(), "10001",UserEntity.class);log.info("user: {}", user);}@Testvoid testGetWithCacheLoader() {UserEntity user = cacheService.get(CacheEnum.USER_INFO.getCacheName(), "10001",UserEntity.class, new CacheLoader<UserEntity>() {@Overridepublic UserEntity load(String key) {return getFakeUser("10001");}});log.info("user: {}", user);}@Testvoid testGetWithSimpledCacheLoader() {UserEntity user = cacheService.get(CacheEnum.USER_INFO.getCacheName(), "10001",UserEntity.class, key -> getFakeUser(key));log.info("user: {}", user);}

第三种就是对于 lambda 接口的简化写法。
基于以上的方式,我们操作缓存就变得更加容易了。

http://www.15wanjia.com/news/623.html

相关文章:

  • 网站开发用户功能分析网站seo查询
  • 遵义在线网站建设新手怎么开始做电商
  • 网站 ca证书怎么做管理培训班
  • 织梦物流公司网站模板简洁大气百度公司销售卖什么的
  • 网站建设与管理适合女生学吗软文营销案例
  • 六数字域名做网站好不好长春网站制作推广
  • 成都手机微信网站建设报价厦门seo起梦网络科技
  • 网站首页改版方案seo推广宣传
  • 哪些专门做批发的网站有哪些基础建站如何提升和优化
  • 自己做投票的网站简述网络营销的概念
  • 做百度推广会送网站吗社交媒体营销
  • 六安网站建设网络服务拼多多代运营收费标准
  • 深圳 网站建设培训班优化百度seo
  • 用ps做的网站样图怎么切100种宣传方式
  • 做企业网站大约多少钱中国十大软件外包公司排名
  • 网站建设 海口热点时事新闻
  • wordpress批量给图片加水印网店seo
  • 博彩网站合作建设seo要点
  • notepad做网站企业网站制作流程
  • 广州建站哪个济南兴田德润实惠吗小广告清理
  • 国外有哪些优秀的网站软文代写自助发稿平台
  • 怎么自己编程做网站百度网络科技有限公司
  • 做门户网站代码质量方面具体需要注意什么临安网站seo
  • 网站建设 外文文献新闻报道最新消息今天
  • 网站建设阶段推广策略市场推广计划怎么写
  • 网站聚合页疫情最新消息
  • 常州做网站哪家好优化神马网站关键词排名价格
  • 人工智能绘画深圳百度推广优化
  • 央美老师做的家具网站淮安网站seo
  • 巩义网站推广优化app推广工作是做什么的