先删缓存再删数据库:
在高并发的情况下会导致缓存击穿(缓存没有线程全部访问数据库造成压力过大)。当第一个线程进来删除缓存,第二个线程进来缓存没有查询数据库然后更新缓存,第一个线程更新数据库,造成脏读。
先删数据库再删缓存:
当一个线程进来更新数据库,另一个线程进来读取缓存,然后第一个线程更新缓存,造成脏读。
异常:
以上情况都没有考虑到异常情况,比如缓存更新失败数据库更新失败。可以做补偿机制。redis也可以做事务处理。
结论:
第一种方式会造成长时间的脏读(通过别的地方了解到延时双删策略就是先删除缓存再更新数据库然后等一段时间在删除缓存,问题是这个一段时间的确定)和缓存击穿,第二种会造成短时间的脏读。一般情况下会用第二种,目前还没遇到高要求的系统。
缓存击穿:
缓存没有线程全部访问数据库造成压力过大。
解决方案:
1.给key设置默认值和失效时间。
2.检查失效时间,每次get出来后对比失效时间,比如小于1分钟更新缓存。
3.查询数据库和更新缓存加锁(吞吐量下降第一个线程进来缓存没有进行更新上锁,第二个线程先进行重试拿缓存有返回,没有sleep,然后再重试拿锁)
缓存雪崩:
缓存同一时间的失效,所以,后面的请求全部访问数据库,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1.将缓存有效时间均匀散开。
2.双缓存,第二个缓存有效时间长,第一个线程进来没有缓存加锁设置缓存,其他线程没有锁读取另一个缓存。