缓存

缓存

缓存,是一种减少I/O读写和CPU计算,以提升性能的手段。

缓存的使用

主要用在需要频繁读某些不变动,或者变动较少的数据的场景。一般使用场景是:应用中使用缓存,需要读数据时,先去缓存中查询。缓存中没有的话,再查数据库,查到数据后返回结果,并将结果写到缓存中。

缓存分类

本地缓存

指应用中的缓存,缓存与应用在同一个进程内部,请求快,无网络开销。缺点是多个应用间无法共享。

实现方式:

一般使用Map实现,考虑多线程安全,则使用ConcurrentHashMap。ID作为key,每次使用id去查缓存。

分布式缓存

缓存是一个独立的应用,多个应用可以共享缓存,可实现持久化。一般使用redis实现

缓存更新问题

如果数据库中的数据有更新,如何更新缓存?

可以采用缓存过期策略,或者定期将数据从数据库中更新到缓存中。

有几种缓存过期策略:

  1. 先进先出。先缓存的数据,先清理。
  2. 最少使用。统计缓存的使用情况,最少使用的数据说明不是热点数据,可以清理掉。
  3. 最近最少使用。最近最少使用的数据,说明数据已经不再是热点数据了,可以清理掉。

满足上述策略的数据会被清理掉,下次访问缓存时再从数据库中读取并更新到缓存中。当然上述策略也是为了释放内存。

另外一种策略是,使用定时任务,在系统负载较低的时候,比如说晚上系统使用人数较少时,从数据库中读取数据,更新到缓存。

如果是应用内的缓存,或者缓存使用并不是很多的情况,并不需要考虑这么复杂的操作。

可以缩小缓存的使用范围,例如缩小到某个方法中,每次请求都清空缓存,再从数据库中读取或者从缓存中读取。这种针对需要在方法中循环处理大量数据,且这批数据中有需要大量读取某个相同值的情况。

例如需要处理一批数据,这批数据中有个字段需要从数据库中获取值,这个字段的值可能相同,不必要处理每条数据时都从数据库中读取,可以每次读取数据后,将值缓存起来,下一条数据先从缓存中读取。

这里定义一个成员变量map作为缓存

private Map<String,String> map;

这个map在什么时候初始化呢?如果在类初始化的时候进行初始化,则存储在map中的数据只有在重启服务后才能清空,重启才能从数据库中获取最新的数据,在此之前读取的数据都是旧。这对数据有变化的情况是不能接受的。

只能在每次处理数据前,初始化map,即是清空map,使得缓存只在这次的请求中生效,这样能保证这次的请求获取的是最新的数据。当然,性能的提升也只是在这次的请求中,下次请求还是先从数据库中读取数据。

架构