转 https://blog.csdn.net/qq_18800463/article/details/79548175
通常使用redis的使用如下:
public Listquery(){ //1.查询缓存 ValueOperations ops = redisTemplate.opsForValue(); String json = String.valueOf(ops.get(CACHE_KEY)); //2.判断缓存中是否有数据 if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){ //返回缓存数据 logger.info("----query for cache----------"); return JSON.parseArray(json,Order.class); } //3.查看数据库,并且返回数据,同时更新缓存 List list = orderMapper.getAll(); ops.set(CACHE_KEY,JSON.toJSON(list),10, TimeUnit.MINUTES); return list; }
当使用多线程 CountDownLatch测试时,会造成缓存击穿
代码如下:
public class CacheTest2 { private static final Logger logger = LoggerFactory.getLogger(CacheTest2.class); private static final int THREAD_NUM = 10; //倒计时器 private CountDownLatch cdl = new CountDownLatch(THREAD_NUM); @Autowired private CacheService cacheService; public void testCache2() throws Exception{ for (int i = 0; i < THREAD_NUM; i++) { new Thread(new QueryTask()).start(); cdl.countDown(); } //主线程休眠 也可以考虑用join Thread.currentThread().sleep(5000); //结果:并发导致缓存失效,使用策略 double check lock (SpringCache) } private class QueryTask implements Runnable{ @Override public void run() { try { cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } Listlist = cacheService.query(); logger.info(list.toString()); } } }
使用双重检查锁:
public /*synchronized */Listquery(){ //1.查询缓存 ValueOperations ops = redisTemplate.opsForValue(); String json = String.valueOf(ops.get(CACHE_KEY)); //2.判断缓存中是否有数据 if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){ //返回缓存数据 logger.info("----query for cache----------"); return JSON.parseArray(json,Order.class); } //Spring Cache //double check lock synchronized (this){ json = String.valueOf(ops.get(CACHE_KEY)); if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){ //返回缓存数据 logger.info("----query for cache----------"); return JSON.parseArray(json,Order.class); } //3.查看数据库,并且返回数据,同时更新缓存 List list = orderMapper.getAll(); ops.set(CACHE_KEY,JSON.toJSON(list),10, TimeUnit.MINUTES); return list; } }
封装成redis缓存查询模板
1.查询接口
public interface CacheLoadable{ public T load(); }
2.查询Service
public ListqueryByTemplate(){ return cacheTemplateService.findCache(CACHE_KEY, 10, TimeUnit.MINUTES, new TypeReference >() { }, new CacheLoadable
>() { @Override public List
load() { return orderMapper.getAll(); } }); }
3.封装成模板
@Component public class CacheTemplateService { @Autowired private RedisTemplate redisTemplate; @Autowired private OrderMapper orderMapper; public static final Logger logger = LoggerFactory.getLogger(CacheTemplateService.class); publicT findCache(String key, long expire, TimeUnit timeUnit, TypeReference clazz, CacheLoadable cacheLoadable){ ValueOperations ops = redisTemplate.opsForValue(); String json = String.valueOf(ops.get(key)); if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){ //返回缓存数据 logger.info("----query for cache----------"); return JSON.parseObject(json,clazz); } synchronized (this){ json = String.valueOf(ops.get(key)); if(!StringUtils.isEmpty(json) || !json.equalsIgnoreCase("null")){ logger.info("----query for cache----------"); return JSON.parseObject(json,clazz); } //核心业务 T result = cacheLoadable.load(); //2-3s ops.set(key,JSON.toJSON(result),expire, timeUnit); return result; } } }