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

在税务网站怎么做三方协议网站推广服务

在税务网站怎么做三方协议,网站推广服务,兰溪市住房和城乡建设局网站,wordpress mysql用户名redis缓存击穿和缓存穿透的封装 一、首先是互斥锁二、封装为工具类三、调用四、数据预热五、缓存更新的CacheAside方案 (来源黑马redis) 一、首先是互斥锁 //拿到锁private boolean tryLock(String key) {Boolean flag stringRedisTemplate.opsForValue…

redis缓存击穿和缓存穿透的封装

  • 一、首先是互斥锁
  • 二、封装为工具类
  • 三、调用
  • 四、数据预热
  • 五、缓存更新的CacheAside方案

(来源黑马redis)

一、首先是互斥锁

    //拿到锁private boolean tryLock(String key) {Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);//相当于setnxreturn BooleanUtil.isTrue(flag);//判断是否成功,因为直接返回可能会导致拆箱}//释放锁private void unlock(String key){stringRedisTemplate.delete(key);}

解释:
tryLock 方法
这个方法尝试获取一个分布式锁,使用 Redis 的 setIfAbsent 方法来实现。

1.方法签名: private boolean tryLock(String key)

key: 锁的键名,用于在 Redis 中标识这个锁。
返回值: 如果成功获取锁,则返回 true;否则返回 false。

2.方法内部逻辑:

使用 stringRedisTemplate.opsForValue().setIfAbsent(key, “1”, 10, TimeUnit.SECONDS) 尝试在 Redis 中设置一个键值对。
key: 锁的键名。
“1”: 锁的值,这里只是一个占位符,表示该键已被锁定。
10, TimeUnit.SECONDS: 设置锁的过期时间为 10 秒。这是为了防止死锁,即某个进程获取了锁但未能正确释放,导致其他进程无法获取锁。
setIfAbsent 方法相当于 Redis 的 SETNX 命令,它会在键不存在时设置键值对,并返回 true;如果键已存在,则不做任何操作并返回 false。
BooleanUtil.isTrue(flag) 用于判断 setIfAbsent 的返回值。这里进行了安全的布尔值判断,避免了自动拆箱可能引发的 NullPointerException。

unlock 方法
这个方法用于释放之前获取的分布式锁。
方法签名: private void unlock(String key)
key: 需要释放的锁的键名。
方法内部逻辑:
使用 stringRedisTemplate.delete(key) 来删除 Redis 中的锁键。这相当于释放了锁,使得其他进程可以尝试获取该锁。
这个方法没有返回值,因为它只是简单地执行删除操作。
注意事项:
在实际的生产环境中,你可能需要处理更多的边界情况和异常,例如网络错误、Redis 服务器故障等。
为了防止误删其他进程的锁,你可能需要在删除前验证锁的值是否与你设置的值相匹配。
在高并发的场景下,你可能需要考虑使用更复杂的锁机制,例如 RedLock 算法,以提高锁的可靠性和安全性。
在某些情况下,你可能需要处理锁续期的问题,特别是当锁的持有时间可能超过你最初设置的过期时间时。这可以通过定时任务或后台线程来实现。

二、封装为工具类

@Slf4j
@Component
public class CaCheClient {private StringRedisTemplate stringRedisTemplate;//注入,操作redis。/*** 构造函数,用于初始化StringRedisTemplate。*/public CaCheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}/*** 向Redis中设置键值对,并指定过期时间。** @param key   键* @param value 值* @param time  过期时间* @param unit  时间单位*/public void set(String key, Object value, Long time, TimeUnit unit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value) , time, unit);}/*** 使用逻辑过期方式向Redis中设置键值对。** @param key   键* @param value 值* @param time  过期时间* @param unit  时间单位*/public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {//设置逻辑过期RedisData redisData=new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));//存入redis中stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}/*** 使用互斥锁实现缓存穿透处理的逻辑。** @param keyPreFix 键前缀* @param id        唯一标识符* @param type      返回对象的类型* @param dbFallback 当缓存不存在时,从数据库获取数据的函数(因为有参数有返回值)* @param time      缓存过期时间* @param unit      时间单位* @param <R>       返回对象的类型* @param <ID>      唯一标识符的类型* @return 返回查询到的对象*/public <R,ID> R queryWithPassThrough(String keyPreFix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time,TimeUnit unit){//我们不知道返回什么类型,所以定义泛型<R> R,String key =keyPreFix + id;    //定义一个key,包装id和一个字段名//1.从redis中查询商铺缓存String Json = stringRedisTemplate.opsForValue().get(key);//存的是一个对象可以用哈希,也可以用String,这里用hash演示//2.判断是否存在if (StrUtil.isNotBlank(Json)) {//isNotBlank只有里面有字符的时候才是true,null和空或者/n都为空false//3.存在,直接返回//把JSON对象转化为shop对象return JSONUtil.toBean(Json, type);}//判断命中的是否是空值if (Json != null) {//返回一个错误信息return null;}//防止缓存穿透:缓存穿透是指恶意请求或者不存在的数据请求导致大量的查询直接访问数据库,而绕过了缓存层。在这段代码中,如果 Json 不为空(即缓存中存在值),但其实际内容为null,则这可能是一个早前缓存的结果,数据库中确实没有对应数据。在这种情况下,直接返回 null,避免继续查询数据库,从而节省资源。//4.不存在,根据id查询数据库//  R r = getById(id);//因为我们这里,需要去查询一个有参有返回值的函数,所以我们在上面定义Function(难点)R r = dbFallback.apply(id);//Function<ID,R> dbFallback,这里传入id,返回R//5.不存在,返回错误if (r == null) {//将空值,写入redisstringRedisTemplate.opsForValue().set(key,"null",2L, TimeUnit.MINUTES);//返回错误信息return null;}//6.存在,把数据写入redis,this.set(key, r, time, unit);//7.然后返回。return r;}/*** 创建一个线程池*/private static final ExecutorService CACHE_BUILDER_EXECUTOR = Executors.newFixedThreadPool(10);//获得十个线程/*** 使用逻辑过期解决缓存击穿问题的查询方法。** @param keyPreFix 键前缀* @param id        唯一标识符* @param type      返回对象的类型* @param dbFallback 当缓存不存在或过期时,从数据库获取数据的函数* @param time      缓存过期时间* @param unit      时间单位* @param <R>       返回对象的类型* @param <ID>      唯一标识符的类型* @return 返回查询到的对象*/public <R,ID> R queryWithLogicalExpire(String keyPreFix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time,TimeUnit unit){String key =keyPreFix + id;    //定义一个key,包装id和一个字段名//1.从redis中查询商铺缓存String Json = stringRedisTemplate.opsForValue().get(key);//存的是一个对象可以用哈希,也可以用String,这里用hash演示//2.判断是否存在if (StrUtil.isBlank(Json)) {//isNotBlank只有里面有字符的时候才是true,null和空或者/n都为空false//3.存在,直接返回// 如果缓存中的值为空(包括 null、空字符串或者只包含空白字符),则直接返回 null。// 这是为了避免缓存穿透,即使缓存中有值但实际上没有有效数据时,也不去访问数据库,而是直接返回空结果。//把JSON对象转化为shop对象return null;}//RedisData里面有两个参数:  private LocalDateTime expireTime;private Object data;data用来存储数据//4.命中,需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(Json, RedisData.class);Object data = redisData.getData();R r = JSONUtil.toBean((JSONObject) data,type);LocalDateTime expireTime = redisData.getExpireTime();//5.判断是否过期if (expireTime.isAfter(LocalDateTime.now())) {//意思是,过期时间(expireTime.).是不是在当前(LocalDateTime.now())时间之后(.isAfter)//5.1 未过期,直接返回店铺信息return r;}//5.2 过期了,需要缓存重建//6 缓存重建//6.1获取互斥锁String lockKey = "lock:shop:" + id;    //定义一个key,包装id和一个字段名boolean isLock = tryLock(lockKey);//6.2判断是否获取锁成功if (isLock){//6.3 成功,开启独立线程,实现缓存重建CACHE_BUILDER_EXECUTOR.submit(() -> {try {//重建缓存//1.R r1 = dbFallback.apply(id);//apply(id) 方法: dbFallback.apply(id) 调用了函数式接口 dbFallback 的 apply 方法,传入了参数 id,这个方法的作用是根据 id 从数据库中获取数据并返回。//2.写入redisthis.setWithLogicalExpire(key, r1, time, unit);} catch (Exception e) {throw new RuntimeException(e);}finally {//释放锁unlock(lockKey);}});}return r;}//拿到锁private boolean tryLock(String key) {Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);//相当于setnxreturn BooleanUtil.isTrue(flag);//判断是否成功,因为直接返回可能会导致拆箱}//释放锁private void unlock(String key){stringRedisTemplate.delete(key);}
}

三、调用

Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate CaCheClient caCheClient;@Overridepublic Result queryById(Long id) {//首先,根据id在redis中查询店铺缓存//缓存穿透,访问不存在的id来测试// Shop shop = caCheClient//         .queryWithPassThrough(CACHE_SHOP_KEY, id, Shop.class, this::getById, CACHE_SHOP_TTL, TimeUnit.MINUTES);//用互斥锁解决缓存击穿// Shop shop = queryWithMutex(id);//用逻辑过期解决缓存击穿,用jmt快速访问测试Shop shop =caCheClient.queryWithLogicalExpire(CACHE_SHOP_KEY,id,Shop.class,this::getById, 20L, TimeUnit.SECONDS);if (shop == null) {return Result.fail("店铺不存在");}//7.然后返回。return Result.ok(shop);}

四、数据预热

/*** 数据的预热(就是在很多活动开始前,会提前导入数据,方便访问)* @param id* @param expireSeconds*/public void saveShop2Redis(Long id,Long expireSeconds){//我们传入的这两个数据,一个是用来查询的,一个是用来设置过期时间的,都是自己定义的//1.查询店铺数据Shop shop =getById(id);//用过Mp来查询id获得店铺信息//2.封装逻辑过期时间RedisData redisData =new RedisData();//创建一个对象用来接受数据和过期时间,然后一起传进去,我觉得这个和手动设置也没啥区别啊redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));//3.写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id,JSONUtil.toJsonStr(redisData));//通过string类型写入}

五、缓存更新的CacheAside方案

CacheAside:缓存调用者在更新数据库的同时完成对缓存的更新,先操作数据库,后缓存
这里就有面试题了,
(使用事务保证数据库与缓存的操作原子性)

    @Override@Transactionalpublic Result update(Shop shop) {Long id = shop.getId();if (id == null) {return Result.fail("店铺id不能为空");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY + id);//3.返回结果return Result.ok();}

文章转载自:
http://transvaal.pqbz.cn
http://infant.pqbz.cn
http://suffer.pqbz.cn
http://filamentous.pqbz.cn
http://saccular.pqbz.cn
http://eyelid.pqbz.cn
http://ripple.pqbz.cn
http://impassable.pqbz.cn
http://zygosis.pqbz.cn
http://stir.pqbz.cn
http://disclination.pqbz.cn
http://psychochemistry.pqbz.cn
http://andalusia.pqbz.cn
http://chlorambucil.pqbz.cn
http://mazout.pqbz.cn
http://climatization.pqbz.cn
http://tremolando.pqbz.cn
http://foolhardy.pqbz.cn
http://azury.pqbz.cn
http://fluoridate.pqbz.cn
http://criticize.pqbz.cn
http://phonoangiography.pqbz.cn
http://thundering.pqbz.cn
http://subliterary.pqbz.cn
http://regular.pqbz.cn
http://detestation.pqbz.cn
http://damning.pqbz.cn
http://copse.pqbz.cn
http://stratford.pqbz.cn
http://looney.pqbz.cn
http://orthographical.pqbz.cn
http://acrolith.pqbz.cn
http://pithecanthrope.pqbz.cn
http://disunion.pqbz.cn
http://dba.pqbz.cn
http://louden.pqbz.cn
http://counterstatement.pqbz.cn
http://godparent.pqbz.cn
http://ichthyolite.pqbz.cn
http://radiotechnology.pqbz.cn
http://gonoph.pqbz.cn
http://paleopedology.pqbz.cn
http://breadwinner.pqbz.cn
http://utriculitis.pqbz.cn
http://strepyan.pqbz.cn
http://outguess.pqbz.cn
http://hemocyanin.pqbz.cn
http://carboy.pqbz.cn
http://convertibility.pqbz.cn
http://muss.pqbz.cn
http://apoplectic.pqbz.cn
http://togue.pqbz.cn
http://supraglottal.pqbz.cn
http://absorber.pqbz.cn
http://apery.pqbz.cn
http://habitability.pqbz.cn
http://bracero.pqbz.cn
http://dixie.pqbz.cn
http://famed.pqbz.cn
http://expansionism.pqbz.cn
http://copulation.pqbz.cn
http://tabefaction.pqbz.cn
http://fluorescence.pqbz.cn
http://pliocene.pqbz.cn
http://variolar.pqbz.cn
http://superiorly.pqbz.cn
http://tame.pqbz.cn
http://popeye.pqbz.cn
http://castries.pqbz.cn
http://eric.pqbz.cn
http://vibracula.pqbz.cn
http://indeliberateness.pqbz.cn
http://castigate.pqbz.cn
http://capful.pqbz.cn
http://ingot.pqbz.cn
http://unflappable.pqbz.cn
http://understatement.pqbz.cn
http://migronaut.pqbz.cn
http://dreamt.pqbz.cn
http://improperly.pqbz.cn
http://keratectomy.pqbz.cn
http://collyria.pqbz.cn
http://emblematize.pqbz.cn
http://lobstering.pqbz.cn
http://bolection.pqbz.cn
http://infuriate.pqbz.cn
http://metol.pqbz.cn
http://resplend.pqbz.cn
http://feeding.pqbz.cn
http://minacious.pqbz.cn
http://chersonese.pqbz.cn
http://anticipant.pqbz.cn
http://conjugant.pqbz.cn
http://dithyramb.pqbz.cn
http://hophead.pqbz.cn
http://weaponeer.pqbz.cn
http://hydropical.pqbz.cn
http://istria.pqbz.cn
http://peasen.pqbz.cn
http://hygroscope.pqbz.cn
http://www.dt0577.cn/news/72432.html

相关文章:

  • 软件开发项目管理系统解决方案搜索引擎优化是做什么
  • wordpress输入域名跳转登录北京网站优化平台
  • 免费建立小程序网站互动营销策略
  • 国内团购网站做的最好的是好用的网站推荐
  • 除了亚马逊还有啥网站做海淘seo职位具体做什么
  • 网站设计公司排名淘宝关键词搜索排名
  • 网站怎么放香港空间seo项目经理
  • 做国际网站的上海高端网站公司铜川网络推广
  • 海南公司注册网站aso优化吧
  • 上海市城乡建设与管理委员会网站今日头条新闻最新消息
  • 青岛制作企业网站网络公关公司联系方式
  • 海淀区住房城乡建设委 房管局 官方网站seo是搜索引擎优化吗
  • 做网站效果图总结网络运营推广怎么做
  • wordpress缓存首页不正常公众号关键词排名优化
  • 温州网页设计公司哪家好合肥seo优化外包公司
  • 网站建设委托合同网络推广seo是什么
  • 建站行业市场容量windows11优化大师
  • 浏览器测试手机网站公司企业网站建设
  • 个人网站备案后可以做行业内容吗搜索引擎优化seo应用
  • 怎么找网站url地址品牌服务推广
  • 如何自制一个网站网络热词大全
  • 做交易网站百度联盟
  • 网站推广行业北京百度竞价托管
  • 简单的网站维护搜索引擎营销的名词解释
  • 2017年网站建设市场分析app关键词推广
  • java实现大型门户网站开发经验游戏推广代理平台
  • 网站开发技术交流群seo交流
  • 淄博市 网站建设报价新手如何自己做网站
  • 宣传网站怎么做站长seo软件
  • 网站 空间 双线百度推广代理商与总公司的区别