Android 历史订单列表缓存,订单缓存查询实践

订单缓存实践

最近在做订单缓存查询相关需求,记录下该过程中缓存查询考虑的几个问题以及处理方案。

缓存穿透

实际场景中使用缓存都是先去缓存中查询,如果缓存没有命中,在去查询数据库并将结果缓存。如果查询一个在系统中根本就不存在的数据,就会造成每次请求都会穿透缓存去查询数据库。如果出现大量的缓存穿透(或者恶意攻击),就会对数据库造成比较大的压力。

处理方案

对于数据库中不存在的数据,存储特定的值表示数据不存在。在发生insert之后将缓存中对应数据移除,避免在数据生成之后缓存中查询还是NULL。

1 publicOrder findById(Long orderId) {2 //从数据库查询

3 Order order =getOrderFromDB(orderId);4 if (order == null) {5 //订单不存在时候填入特定"NULL"表示订单不存在

6 putOrderToCache(orderId, "NULL");7 } else{8 putOrderToCache(orderId, order);9 }10 returnorder;11 }

缓存并发

在查询同一并发量较大情况下,如果该订单缓存失效,就会造成这一瞬间所有的订单查询请求都会访问到数据库,造成数据库压力增大。

处理方案

并发查询同一订单,缓存中不存在,加锁查询数据库,其余请求等待获取锁或者获取超时返回数据或者查询数据库。

publicOrder findById(Long orderId) {//从缓存中获取

Result result =getOrderFromCache(orderId);

Order order=result.getOrder();if(result.isEmpty()) {//从DB获取数据

order =getOrderFromDB(orderId);//写入缓存

putOrderToCache(orderId, order);

}returnorder;

}

上面这种写法,一般是没什么问题,在并发量大时候会造成所有请求都查询到数据库。并发100个请求查询同一个订单,当缓存没数据时100请求都会到DB。为了处理这种情况,解决的方式就是加锁。

publicOrder findById(Long orderId) {//从缓存中获取

Result result =getOrderFromCache(orderId);

Order order=result.getOrder();if(result.isEmpty()) {try{if (lock.tryLock(1)) {//从DB获取数据

order =getOrderFromDB(orderId);//写入缓存

putOrderToCache(orderId, order);

}else{

Thread.sleep(10);//10毫秒根据业务场景自定义

returnfindById(orderId);

}

}catch(Exception e) {// } finally{

lock.unlock();

}

}returnorder;

}

尝试获取一次锁,并发情况下,获取不到锁就重新走一遍流程(先查缓存,在查DB),加锁时间不要设置太长,避免过多的线程在等待。采用这种方式,当有100个请求并发查询时候,一个线程拿到锁查询DB,剩余99个线程在等待10毫秒重试,比如查询DB线程获取到数据需要耗时5毫秒,10毫秒之后99个线程发现缓存中有值,直接从缓存中取值,耗时10毫秒。

缓存失效

为了避免缓存中的数据越来越多或者缓存一些很少用到或者根本不会使用到数据,通常都会在订单缓存中加入过期时间,比如几分钟。当某些情况下,会出现多个订单的过期时间是一样的,即多个订单缓存数据同时失效。

处理方案

对于每个订单的缓存失效时间都不一样,失效时间都是一个范围内随机值,可以在一定程度上减少缓存同时失效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值