使用 java 开发程序时,如果我们想保存当前用户信息,让其他的方法调用。我们可以使用这几种方法:
- session 这个容器中
- 创建一个静态的 HashMap 容器用来保存信息
- 使用 ThreadLocal 保存信息
但是这几个方法都有一个弊端:它们只适合单机的情况,如果是在集群环境下,多台 JVM 机之间的信息是无法共享的
所以在集群环境下,我们要考虑共享存储这个问题。那样就不能再 java 程序中去存储信息。我们要使用一个独立于 java 程序的 容器存储数据。 这里我们就可以使用 redis 来存储数据
缓存数据
介绍缓存数据前,我们假设一个业务场景:如果我们要查询一个商铺的信息。前端发出请求,后端向数据库发出请求,将数据查出来,返回给前端。如果我们要查询的是 100 个商铺呢 ? 是 1000 个呢 ? 如果数据更大的话,查询数据库的时间就要非常久。有什么办法可以减少查询数据库的时间吗 ?
如果我们可以将要查询的数据保存好在一个容器中,用户发起请求,直接访问这个容器,而不用去查询数据库,响应的时间是不是大大减少了。这就是我要介绍的缓存。这里我们使用 redis 这个数据库来缓存数据
1. 什么是缓存
缓存 就是数据交换的缓冲区(称作Cache),是存贮数据的临时地方,一般读写性能较高。
2.缓存的利与弊
缓存的作用:
- 降低后端负载
- 提高读写效率,降低响应时间
缓存的成本:
- 数据一致性的成本
- 代码维护的成本
3.缓存作用的模型
4. 缓存更新
-
缓存数据,缓存的是旧的数据,如果我们修改了数据库的数据,那么缓存的数据要不要修改呢 ? 如果不修改的话,就会出现一个数据不一致的问题。
-
redis 缓存数据,默认是不会删除的,如果所有的数据都不删除,那么 redis 的内存是不是迟早会满。所以我们应该设置过期时间
4.1.缓存更新的策略:
- 内存淘汰
- 超时删除
- 主动更新
对于高一致性的需求,我们可以采用主动更新,并以过期时间作为兜底方案
对于低一致性的需要,我们可以采用内存淘汰机制,但是最好还是加上过期时间
4.2. 操作缓存和数据库时有三个问题需要考虑
- 删除缓存还是更新缓存 ?
- 更新缓存:每次更新数据库都更新缓存,无效操作较多
- 删除缓存:更新数据库时让缓存失效,查询时在更新缓存 √
- 如何保证缓存与数据库的操作的同时成功或失败 ?(原子性问题)
- 单体系统,将缓存与数据库操作放在一个事务中
- 先操作缓存还是先操作数据库 ?(线程安全问题)
- 先删除缓存,再操作数据库
- 先操作数据库,再删除缓存 √
4.3.主动更新的实践
-
读操作
- 缓存命中则直接返回数据
- 缓存未命中则查询数据库,并写入缓存,设置超时时间
-
写操作
- 先写数据库,然后删除缓存
- 确保数据库与缓存操作的原子性