缓存 cache springcache 素颜马尾好姑娘i 2022-01-17 16:47 305阅读 0赞 [2019独角兽企业重金招聘Python工程师标准>>> ][2019_Python_] ![hot3.png][] 滑动过期: 每访问一次 过期时间往后延迟一次 即执行一次 redisTemplate.expire(provinceid,20000, TimeUnit.MILLISECONDS); ![4e8d3a64b2531c0e7f7d426841fd1a39746.jpg][] ![ff33e7bc8a39ca7ed688e89f028d21c02c9.jpg][] ![2e858867dd3edaf88812df3e79b28cd3ed6.jpg][] ![76a6d825b37ff3db23a12860f82e779dcab.jpg][] @Cacheable(value = "province", key = "#root.targetClass.simpleName+':'+#root.methodName+':'+#provinceid")// value指定当前接口,要使用哪一个缓存器 --- 如果该缓存器不存在,则会自动创建 // 如果不指定key,spring将会自动将方法入参作为key ![cd09fbcaf933169e222047edfaf70b9fd99.jpg][] ![03ddf3ea8ebe311518616751cea5a25174b.jpg][] //组合配置 同时更新两个缓存器中指定key的数据 @Caching(put = { @CachePut(value = "province",key = "#entity.provinceid"), @CachePut(value = "city",key = "#entity.provinceid")} ) public Provinces add(Provinces entity) { provincesDao.insert(entity); return entity; } @CacheConfig(cacheNames="province") //通用配置 声明缓存器名称 即使此处不声明 在 @Cacheable(value = "province")时 将会被自动创建 // 一旦声明了cacheNames 在使用@Cacheable时,则可以不指定value 如果配置了多个cacheName @CacheConfig(cacheNames={"province","city"}) 则相当于 @Cacheable(value //= {"province","city"}) ![29bbcc75b020663c8ef6ac1b9993f8a6d66.jpg][] ![ef0ab6accf91b24bbb4cf21544fc707ffcb.jpg][] package com.enjoy.service; import com.enjoy.entity.Provinces; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 缓存雪崩 不能使用 @Cacheable */ @Service("provincesService3") public class ProvincesServiceImpl3 extends ProvincesServiceImpl implements ProvincesService{ private static final Logger logger = LoggerFactory.getLogger(ProvincesServiceImpl3.class); @Resource private CacheManager cm; private ConcurrentHashMap<String, Lock> locks = new ConcurrentHashMap<>();//线程安全的 private static final String CACHE_NAME = "province"; public Provinces detail(String provinceid) { // 1.从缓存中取数据 Cache.ValueWrapper valueWrapper = cm.getCache(CACHE_NAME).get(provinceid); if (valueWrapper != null) { logger.info("缓存中得到数据"); return (Provinces) (valueWrapper.get()); } //2.加锁排队,阻塞式锁 doLock(provinceid);//32个省,最多只有32把锁,1000个线程 try{//第二个线程进来了 // 一次只有一个线程 //双重校验,不加也没关系,无非是多刷几次库 valueWrapper = cm.getCache(CACHE_NAME).get(provinceid);//第二个线程,能从缓存里拿到值? if (valueWrapper != null) { logger.info("缓存中得到数据"); return (Provinces) (valueWrapper.get());//第二个线程,这里返回 } Provinces provinces = super.detail(provinceid); // 3.从数据库查询的结果不为空,则把数据放入缓存中,方便下次查询 if (null != provinces){ cm.getCache(CACHE_NAME).put(provinceid, provinces); } return provinces; }catch(Exception e){ return null; }finally{ //4.解锁 releaseLock(provinceid); } } private void releaseLock(String userCode) { ReentrantLock oldLock = (ReentrantLock) locks.get(userCode); if(oldLock !=null && oldLock.isHeldByCurrentThread()){ oldLock.unlock(); } } private void doLock(String lockcode) { //provinceid有不同的值,参数多样化 //provinceid相同的,加一个锁,---- 不是同一个key,不能用同一个锁 ReentrantLock newLock = new ReentrantLock();//创建一个锁 Lock oldLock = locks.putIfAbsent(lockcode, newLock);//若已存在,则newLock直接丢弃 if(oldLock == null){ newLock.lock(); }else{ oldLock.lock(); } } } ![26d1aa3a7f68426851ff0c3e902731c4d46.jpg][] package com.enjoy.service; import com.enjoy.entity.Provinces; import com.google.common.base.Charsets; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.List; /** * 缓存穿透 */ @Service("provincesService4") public class ProvincesServiceImpl4 extends ProvincesServiceImpl implements ProvincesService{ private BloomFilter<String> bf =null; //等效成一个set集合 @PostConstruct //对象创建后,自动调用本方法 public void init(){//在bean初始化完成后,实例化bloomFilter,并加载数据 List<Provinces> provinces = this.list(); //当成一个SET----- 占内存,比hashset占得小很多 bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), provinces.size());// 32个 for (Provinces p : provinces) { bf.put(p.getProvinceid()); } } @Cacheable(value = "province") public Provinces detail(String provinceid) { //先判断布隆过滤器中是否存在该值,值存在才允许访问缓存和数据库 if(!bf.mightContain(provinceid)){ System.out.println("非法访问--------"+System.currentTimeMillis()); return null; } System.out.println("数据库中得到数据--------"+System.currentTimeMillis()); Provinces provinces = super.detail(provinceid); return provinces; } @CachePut(value = "province",key = "#entity.provinceid") public Provinces update(Provinces entity) { super.update(entity); return entity; } @CacheEvict(value = "province",key = "#entity.provinceid") public Provinces add(Provinces entity) { super.add(entity); return entity; } @Override @CacheEvict("province") public void delete(String provinceid) { super.delete(provinceid); } } 转载于:https://my.oschina.net/u/2351011/blog/3059745 [2019_Python_]: https://my.oschina.net/u/2663968/blog/3061697 [hot3.png]: /images/20220114/f309a6a333c447788e6fd8f9819c6387.png [4e8d3a64b2531c0e7f7d426841fd1a39746.jpg]: /images/20220114/5f306be7bd7f4df197a6ee013a362ac2.png [ff33e7bc8a39ca7ed688e89f028d21c02c9.jpg]: /images/20220114/deb5f967900f4db5b238634f8f6e1235.png [2e858867dd3edaf88812df3e79b28cd3ed6.jpg]: /images/20220114/be51a054c89f489497a283ec1fa755f3.png [76a6d825b37ff3db23a12860f82e779dcab.jpg]: /images/20220114/12cd1d261768400eb01b7557d2f81268.png [cd09fbcaf933169e222047edfaf70b9fd99.jpg]: /images/20220114/c6dddf62571242f2883feab2bda5140d.png [03ddf3ea8ebe311518616751cea5a25174b.jpg]: /images/20220114/c8548793bf1b4d778039cebe4c900596.png [29bbcc75b020663c8ef6ac1b9993f8a6d66.jpg]: /images/20220114/2197e6600e404aeaaf79f73ddaa5ce42.png [ef0ab6accf91b24bbb4cf21544fc707ffcb.jpg]: /images/20220114/0b04e3feafb248deb46b412d0c51a57b.png [26d1aa3a7f68426851ff0c3e902731c4d46.jpg]: /images/20220114/39bb3d7bf7bd4df0a1ec9ec4bf660756.png
还没有评论,来说两句吧...