缓存空对象的使用

缓存空对象作为一种性能优化策略,可以防止数据库被击穿并减少恶意攻击。当数据库未命中时,将空对象存入缓存,避免后续重复访问。然而,大量分散的无效访问可能导致缓存容量膨胀,因此应谨慎使用。该策略适用于无效数据高频度访问的内部服务应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     缓存空对象是一种用空间换其他资源(时间、IO、CPU)的技术,可以有效的防止数据库被击穿,并一度程序上减少恶意攻击(特别是将Cache做到client本地)。
     普通使用缓存的场景是,将请求从数据库中读出数据返回的时候,将读出的正常数据写到缓存。而空缓存的意思是,如果请求在数据库中没有命中,依然在缓存中放入一个空缓存对象,这样的话,以后请求过来时访问缓存就会命中这个空缓存,它也就明白了自己的要查的数据不存在,从而避免访问数据库。
     
普通使用缓存的代码,例:
public class UserManager {
     UserDAO userDAO;
     LocalCache localCache;

     public UserDO getUser(String userNick) {
          UserDO user = (UserDO)localCache.get(userNick);
          if(user == null) {
               user = userDAO.getUser(userNick);
               if(user != null) {
                    localCache.put(userNick,user);
               }
          }
          return user;
     }          
}

使用空缓存对象的示例:
public class NullValueResultDO implements Serializable{
     private static final long serialVersionUID = -6550539547145486005L;
}

public class UserManager {
     UserDAO userDAO;
     LocalCache localCache;

     public UserDO getUser(String userNick) {
          Object object = localCache.get(userNick);
          if(object != null) {
               if(object instanceof NullValueResultDO) {
                    return null;
               }
               return (UserDO)object;
          } else {
               User user = userDAO.getUser(userNick);
               if(user != null) {
                    localCache.put(userNick,user);
               } else {
                    localCache.put(userNick, new NullValueResultDO());
               }
               return user;
          }
     }          
}

     缓存空对象可没想象中的那么尽善尽美,对于大量分散的失效的访问会造成缓存容量的膨胀,这可算是一种内存攻击,即使缓存采用LRU实现,也会挤压其他正常数据的空间,所以对于缓存空对象要慎用。缓存空对象最适用于集中地无效数据高频度访问的状况,这种状况可能最适用于内部服务的应用,这种服务应用的请求无效数据的较少,但频度较高。


### 如何在 Redis 中缓存对象 为了有效地利用 Redis 缓存 Java 对象,通常会采用序列化的方式将对象转换成字符串形式存储于 Redis 中。当需要获取该对象时再将其反序列化回原始的对象形态。 #### 使用 `@Cacheable` 注解实现查询套餐缓存 可以直接在方法上添加 `@Cacheable` 注解并指定缓存名称以及构造用于 Redis 存储键值[^1]: ```java @Cacheable(value = "packageCache", key = "#id") public Package getPackageById(Long id) { // 查询数据库逻辑... } ``` 此方式简化了开发流程,使得开发者无需手动编写复杂的缓存管理代码即可轻松完成基本的缓存功能。 #### 处理读取 DB 方法返回的数据为空的情况 对于从数据库中未能成功检索到记录的情形下是否应该保存至 Redis 这一问题,则取决于业务需求。某些场景可能允许设置开关控制这种行为的发生与否[^2]。例如,在配置文件中定义属性决定是否开启此类特性;而在实际编码过程中则依据此配置项执行相应的分支处理路径。 #### 预防常见问题——缓存雪崩现象 为了避免大量缓存在同一时刻失效进而引发服务器压力骤增的问题(即所谓的“缓存雪崩”),可以采取为不同条目的 TTL 设置随机增量的方法来分散这些事件的时间分布[^3]。这有助于减轻因集中式的过期而导致的服务负载高峰。 #### 封装逻辑过期时间重置机制 考虑到缓存重建期间需同步更新其有效期限这一诉求,可设计专门负责此项工作的函数以便灵活调整各个实例的有效时段长度[^4]。下面给出了一段示范性的源码片段展示了怎样把一个商店实体及其对应的截止日期组合起来并通过 JSON 序列化的手段送入 Redis 内部: ```java public void saveShopToRedis(Long id, Long seconds) { // 1. 查询店铺数据 Shop shop = getById(id); // 创建包含店铺信息和有效期的对象 RedisData redisData = new RedisData(); redisData.setData(shop); redisData.setExpireTime(LocalDateTime.now().plusSeconds(seconds)); // 2. 将上述复合体转化为JSON串后存入Redis stringRedisTemplate.opsForValue() .set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData)); } ``` 以上就是关于如何运用 Redis 来高效地管理和维护应用程序内的对象级缓存的一些指导方针和技术细节介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值