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

网站建设公司销售求几个微信推广平台

网站建设公司销售,求几个微信推广平台,济宁做网站比较好的公司有哪些,怎么弄网站关键词文章目录 前言IBloomFilterObjectMapUtilsCacheClient使用示例具体业务的布隆过滤器控制层服务层 前言 该工具类包含以下功能: 1.将任意对象存储在 hash 类型的 key 中,并可以设置 TTL 2.将任意对象存储在 hash 类型的 key 中,并且可以设置…

文章目录

  • 前言
  • IBloomFilter
  • ObjectMapUtils
  • CacheClient
  • 使用示例
    • 具体业务的布隆过滤器
    • 控制层
    • 服务层

前言

该工具类包含以下功能:

1.将任意对象存储在 hash 类型的 key 中,并可以设置 TTL

2.将任意对象存储在 hash 类型的 key 中,并且可以设置逻辑过期时间

3.将空对象存入 hash 类型的 key 中,并且可以设置超时时间

4.缓存空对象解决缓存穿透

5.布隆过滤器解决缓存穿透

6.布隆过滤器+缓存空对象解决缓存穿透

7.互斥锁解决缓存击穿

8.逻辑过期解决缓存击穿

以下是关键代码

IBloomFilter

IBloomFilter 是自定义的布隆过滤器接口。这里使用接口的原因在于,每个业务使用的布隆过滤器可能是不一样的,因此为了让工具类能兼容所有的布隆过滤器,这里添加接口,并使用泛型表示布隆过滤器内部存储数据的类型

public interface IBloomFilter<T> {// 添加void add(T id);// 判断是否存在boolean mightContain(T id);}

ObjectMapUtils

ObjectMapUtils 是对象与 Map 类型的相互转换,可以让对象转换为 Map 集合,也可以让 Map 集合转回对象

public class ObjectMapUtils {// 将对象转为 Mappublic static Map<String, String> obj2Map(Object obj) throws IllegalAccessException {Map<String, String> result = new HashMap<>();Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 如果为 static 且 final 则跳过if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) {continue;}field.setAccessible(true); // 设置为可访问私有字段Object fieldValue = field.get(obj);if (fieldValue != null) {result.put(field.getName(), field.get(obj).toString());}}return result;}// 将 Map 转为对象public static<R> R map2Obj(Map<Object, Object> map, Class<R> clazz) throws Exception {R obj = clazz.getDeclaredConstructor().newInstance();for (Map.Entry<Object, Object> entry : map.entrySet()) {Object fieldName = entry.getKey();Object fieldValue = entry.getValue();Field field = clazz.getDeclaredField(fieldName.toString());field.setAccessible(true); // 设置为可访问私有字段String fieldValueStr = fieldValue.toString();// 根据字段类型进行转换fillField(obj, field, fieldValueStr);}return obj;}// 将 Map 转为对象(含排除字段)public static<R> R map2Obj(Map<Object, Object> map, Class<R> clazz, String... excludeFields) throws Exception {R obj = clazz.getDeclaredConstructor().newInstance();for (Map.Entry<Object, Object> entry : map.entrySet()) {Object fieldName = entry.getKey();if(Arrays.asList(excludeFields).contains(fieldName)) {continue;}Object fieldValue = entry.getValue();Field field = clazz.getDeclaredField(fieldName.toString());field.setAccessible(true); // 设置为可访问私有字段String fieldValueStr = fieldValue.toString();// 根据字段类型进行转换fillField(obj, field, fieldValueStr);}return obj;}// 填充字段private static void fillField(Object obj, Field field, String value) throws IllegalAccessException {if (field.getType().equals(int.class) || field.getType().equals(Integer.class)) {field.set(obj, Integer.parseInt(value));} else if (field.getType().equals(boolean.class) || field.getType().equals(Boolean.class)) {field.set(obj, Boolean.parseBoolean(value));} else if (field.getType().equals(double.class) || field.getType().equals(Double.class)) {field.set(obj, Double.parseDouble(value));} else if (field.getType().equals(long.class) || field.getType().equals(Long.class)) {field.set(obj, Long.parseLong(value));} else if (field.getType().equals(String.class)) {field.set(obj, value);} else if(field.getType().equals(LocalDateTime.class)) {field.set(obj, LocalDateTime.parse(value));}// 如果有需要可以继续添加...}}

CacheClient

CacheClient 就是缓存工具类,包含了之前提到的所有功能

@Component
@Slf4j
public class CacheClient {@Autowiredprivate StringRedisTemplate redisTemplate;// 重建缓存线程池private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);// 将任意对象存储在 hash 类型的 key 中,并可以设置 TTLpublic void setByHash(String key, Object value, Long time, TimeUnit unit) throws IllegalAccessException {redisTemplate.opsForHash().putAll(key, ObjectMapUtils.obj2Map(value));redisTemplate.expire(key, time, unit);}// 将任意对象存储在 hash 类型的 key 中,并且可以设置逻辑过期时间public void setWithLogicalExpireByHash(String key, Object value, Long time, TimeUnit unit) throws IllegalAccessException {Map<String, String> map = ObjectMapUtils.obj2Map(value);// 添加逻辑过期时间map.put(RedisConstants.EXPIRE_KEY, LocalDateTime.now().plusSeconds(unit.toSeconds(time)).toString());redisTemplate.opsForHash().putAll(key, map);}// 将空对象存入 hash 类型的 key 中,并且可以设置超时时间public void setNullByHash(String key, Long time, TimeUnit unit) {redisTemplate.opsForHash().put(key, "", "");redisTemplate.expire(key, time, unit);}// 尝试加锁private boolean tryLock(String key, Long time, TimeUnit unit) {Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(key,"1", time, unit);return Boolean.TRUE.equals(isLocked);}// 解锁private void unlock(String key) {redisTemplate.delete(key);}// 缓存空对象解决缓存穿透public<R, ID> R queryWithCacheNull(String keyPrefix, ID id, Class<R> clazz, Function<ID, R> dbFallback,Long time, TimeUnit unit) {// 从 redis 查询String key = keyPrefix + id;Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);// 缓存命中if (!entries.isEmpty()) {try {// 如果是空对象,表示一定不存在数据库中,直接返回(解决缓存穿透)if (entries.containsKey("")) {log.info("redis查询到id={}的空对象,", id);return null;}// 刷新有效期redisTemplate.expire(key, time, unit);R r = ObjectMapUtils.map2Obj(entries, clazz);log.info("缓存命中,结果为:{}", r);return r;} catch (Exception e) {throw new RuntimeException(e);}}// 查询数据库R r = dbFallback.apply(id);if (r == null) {log.info("id={}不存在于数据库,存入redis", id);// 存入空值setNullByHash(key, RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);// 不存在,直接返回return null;}// 存在,写入 redistry {setByHash(key, r, time, unit);} catch (IllegalAccessException e) {throw new RuntimeException(e);}log.info("查询数据库,获取结果:{}", r);return r;}// 布隆过滤器解决缓存穿透public<R, ID> R queryWithBloom(String keyPrefix, ID id, Class<R> clazz, Function<ID, R> dbFallback,Long time, TimeUnit unit, IBloomFilter<ID> bloomFilter) {// 如果不在布隆过滤器中,直接返回if (!bloomFilter.mightContain(id)) {log.info("id={}不存在于布隆过滤器", id);return null;}// 从 redis 查询String key = keyPrefix + id;Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);// 缓存命中if (!entries.isEmpty()) {try {// 刷新有效期redisTemplate.expire(key, time, unit);R r = ObjectMapUtils.map2Obj(entries, clazz);log.info("缓存命中,结果为:{}", r);return r;} catch (Exception e) {throw new RuntimeException(e);}}// 查询数据库R r = dbFallback.apply(id);if (r == null) {log.info("id={}不存在于数据库", id);// 不存在,直接返回return null;}// 存在,写入 redistry {setByHash(key, r, time, unit);} catch (IllegalAccessException e) {throw new RuntimeException(e);}log.info("查询数据库,获取结果:{}", r);return r;}// 布隆过滤器+缓存空对象解决缓存穿透public<R, ID> R queryWithBloomAndCacheNull(String keyPrefix, ID id, Class<R> clazz, Function<ID, R> dbFallback,Long time, TimeUnit unit, IBloomFilter<ID> bloomFilter) {// 如果不在布隆过滤器中,直接返回if (!bloomFilter.mightContain(id)) {log.info("id={}不存在于布隆过滤器", id);return null;}// 从 redis 查询String key = keyPrefix + id;Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);// 缓存命中if (!entries.isEmpty()) {try {// 如果是空对象,表示一定不存在数据库中,直接返回(解决缓存穿透)if (entries.containsKey("")) {log.info("redis查询到id={}的空对象,", id);return null;}// 刷新有效期redisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);R r = ObjectMapUtils.map2Obj(entries, clazz);log.info("缓存命中,结果为:{}", r);return r;} catch (Exception e) {throw new RuntimeException(e);}}// 查询数据库R r = dbFallback.apply(id);if (r == null) {log.info("id={}不存在于数据库,存入redis", id);// 存入空值setNullByHash(key, RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);// 不存在,直接返回return null;}// 存在,写入 redistry {setByHash(key, r, time, unit);} catch (IllegalAccessException e) {throw new RuntimeException(e);}log.info("查询数据库,获取结果:{}", r);return r;}// 互斥锁解决缓存击穿public<R, ID> R queryWithMutex(String keyPrefix, ID id, Class<R> clazz, Function<ID, R> dbFallback,Long cacheTime, TimeUnit cacheUnit, String lockKeyPrefix,Long lockTime, TimeUnit lockUnit) {String key = keyPrefix + id;String lockKey = lockKeyPrefix + id;boolean flag = false;int cnt = 10; // 重试次数try {do {// 从 redis 查询Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);// 缓存命中if (!entries.isEmpty()) {try {// 刷新有效期redisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);R r = ObjectMapUtils.map2Obj(entries, clazz);log.info("缓存命中,结果为:{}", r);return r;} catch (Exception e) {throw new RuntimeException(e);}}// 缓存未命中,尝试获取互斥锁log.info("缓存未命中,尝试获取互斥锁 id={}", id);flag = tryLock(lockKey, lockTime, lockUnit);if (flag) { // 获取成功,进行下一步log.info("成功获取互斥锁 id={}", id);break;}// 获取失败,睡眠后重试Thread.sleep(50);} while ((--cnt) != 0); // 未获取到锁,休眠后重试if(!flag) { // 重试次数到达上限log.info("重试次数达到上限 id={}", id);return null;}// 查询数据库R r = dbFallback.apply(id);if (r == null) {log.info("id={}不存在于数据库", id);// 不存在,直接返回return null;}// 存在,写入 redistry {setByHash(key, r, cacheTime, cacheUnit);} catch (IllegalAccessException e) {throw new RuntimeException(e);}log.info("查询数据库,获取结果:{}", r);return r;} catch (InterruptedException e) {throw new RuntimeException(e);} finally {if (flag) { // 获取了锁需要释放log.info("解锁id={}", id);unlock(lockKey);}}}// 逻辑过期解决缓存击穿public<R, ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> clazz, Function<ID, R> dbFallback,Long expireTime, TimeUnit expireUnit,String lockKeyPrefix, Long lockTime, TimeUnit lockUnit) {String key = keyPrefix + id;String lockKey = lockKeyPrefix + id;// 从 redis 查询Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);// 缓存未命中,返回空if(entries.isEmpty()) {log.info("缓存未命中,返回空 id={}", id);return null;}try {R r = ObjectMapUtils.map2Obj(entries, clazz, RedisConstants.EXPIRE_KEY);LocalDateTime expire = LocalDateTime.parse(entries.get(RedisConstants.EXPIRE_KEY).toString());// 判断缓存是否过期if(expire.isAfter(LocalDateTime.now())) {// 未过期则直接返回log.info("缓存未过期,结果为;{}", r);return r;}// 过期需要先尝试获取互斥锁log.info("尝试获取互斥锁 id={}", id);if(tryLock(lockKey, lockTime, lockUnit)) {log.info("获得到互斥锁 id={}", id);// 获取成功// 双重检验entries = redisTemplate.opsForHash().entries(key);r = ObjectMapUtils.map2Obj(entries, clazz, RedisConstants.EXPIRE_KEY);expire = LocalDateTime.parse(entries.get(RedisConstants.EXPIRE_KEY).toString());if(expire.isAfter(LocalDateTime.now())) {// 未过期则直接返回log.info("缓存未过期,结果为;{}", r);log.info("解锁 id={}", id);unlock(lockKey);return r;}// 通过线程池完成重建缓存任务CACHE_REBUILD_EXECUTOR.submit(() -> {try {log.info("进行重建缓存任务 id={}", id);setWithLogicalExpireByHash(key, dbFallback.apply(id), expireTime, expireUnit);} catch (Exception e) {throw new RuntimeException(e);} finally {log.info("解锁 id={}", id);unlock(lockKey);}});}log.info("返回结果:{}", r);return r;} catch (Exception e) {throw new RuntimeException(e);}}}

使用示例

具体业务的布隆过滤器

public class ShopBloomFilter implements IBloomFilter<Long> {private BloomFilter<Long> bloomFilter;public ShopBloomFilter(ShopMapper shopMapper) {// 初始化布隆过滤器,设计预计元素数量为100_0000L,误差率为1%bloomFilter = BloomFilter.create(Funnels.longFunnel(), 100_0000, 0.01);// 将数据库中已有的店铺 id 加入布隆过滤器List<Shop> shops = shopMapper.selectList(null);for (Shop shop : shops) {bloomFilter.put(shop.getId());}}public void add(Long id) {bloomFilter.put(id);}public boolean mightContain(Long id){return bloomFilter.mightContain(id);}}

控制层

/*** 根据id查询商铺信息* @param id 商铺id* @return 商铺详情数据*/
@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {return shopService.queryShopById(id);
}

服务层

@Override
public Result queryShopById(Long id) {// 缓存空对象解决缓存穿透/*Shop shop = cacheClient.queryWithCacheNull(RedisConstants.CACHE_SHOP_KEY,id, Shop.class, this::getById, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);*/// 布隆过滤器解决缓存穿透/*Shop shop = cacheClient.queryWithBloom(RedisConstants.CACHE_SHOP_KEY,id, Shop.class, this::getById, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES, shopBloomFilter);*/// 布隆过滤器+缓存空对象解决缓存穿透/*Shop shop = cacheClient.queryWithBloomAndCacheNull(RedisConstants.CACHE_SHOP_KEY,id, Shop.class, this::getById, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES, shopBloomFilter);*/// 互斥锁解决缓存击穿/*Shop shop = cacheClient.queryWithMutex(RedisConstants.CACHE_SHOP_KEY, id, Shop.class, this::getById,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES,RedisConstants.LOCK_SHOP_KEY, RedisConstants.LOCK_SHOP_TTL, TimeUnit.SECONDS);*/// 逻辑过期解决缓存击穿Shop shop = cacheClient.queryWithLogicalExpire(RedisConstants.CACHE_SHOP_KEY, id, Shop.class, this::getById,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES,RedisConstants.LOCK_SHOP_KEY, RedisConstants.LOCK_SHOP_TTL, TimeUnit.SECONDS);if(shop == null) {return Result.fail("商铺不存在");}return Result.ok(shop);
}
http://www.qdjiajiao.com/news/2176.html

相关文章:

  • 营销型网站建设排名浏览器大全网站
  • 自己做网站怎么挣钱餐饮管理培训课程
  • 那些网站企业可以免费展示百度明星人气榜入口
  • 网站建设 搜狐号引流推广网站平台
  • 济南做网站互联网公司长春刚刚最新消息今天
  • axure做的是静态网站品牌营销包括哪些方面
  • 今日国内重大新闻seo推广和百度推广的区别
  • 迅速编程做网站百青藤广告联盟
  • 有做酒席酒水网站吗如何自己创造一个网站平台
  • 连云港企业网站建设公司360网址大全
  • 网站目录结构 权限长沙seo外包平台
  • 怎样设计app软件百度关键词搜索优化
  • 苏州教育学会网站建设今日国际重大新闻
  • 网站建设个人兼职房产网站建设
  • 免费下ppt课件的网站友谊平台
  • 嘉兴免费网站建站模板网络推广方式方法
  • 网站建设提成互联网项目推广平台有哪些
  • 南京h5网站开发短视频推广平台有哪些
  • 搜索引擎营销的优势百度刷seo关键词排名
  • dw制作班级网站广告搜索引擎
  • 网易企业邮箱怎么发送文件平台seo
  • 公司做网站的费用怎么记账品牌推广方案思维导图
  • 称多县网站建设公司舆情分析报告范文
  • 东莞网站建设网站建立坚持
  • 辽阳网站推广预防电信网络诈骗
  • 股票网站开发拉新人拿奖励的app
  • wordpress 新建导航seo排名啥意思
  • seo做的最好的网站排行seo课程总结怎么写
  • 期刊类网站建设福州seo网站排名
  • 网站制作知名公司windows优化大师怎么用