实现自定义缓存的最佳做法?


17

对于每种实体类型的每个实例,我都会生成许多缓存,它们的名称如下: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

现在,无论何时更新实体,我都希望删除所有从相关实体类型和ID开始的缓存。

我应该如何存储/清除这些缓存?

当前,我只是cache_set(),但是在我要清除时出现了一个问题,因为我不知道所有相关缓存的名称。使用db_delete()删除缓存条目是否安全?


如果您不知道所有相关缓存的名称,该如何使用db_delete()
kiamlaluno

Answers:


6

要从缓存中删除条目,应使用cache_clear_all()。原因是所使用的缓存实现无法使用活动数据库中的数据库表。这就是DrupalDatabaseCache类所发生的情况,但并非每个类都正确。

如果查看_cache_get_object()(由cache_get()cache_set()调用的函数),您会注意到它包含以下代码。

  static $cache_objects; 
  if (!isset($cache_objects[$bin])) {
    $class = variable_get('cache_class_' . $bin);
    if (!isset($class)) {
      $class = variable_get('cache_default_class', 'DrupalDatabaseCache');
    }
    $cache_objects[$bin] = new $class($bin);
  }
  return $cache_objects[$bin];

每个缓存bin存储的缓存实现类可能会有所不同,甚至可以更改默认类。

私有更新状态缓存系统准确地解释了为什么在_update_cache_clear()_update_cache_get()_update_cache_set()中不使用常规缓存功能的原因。(强调是我的。)

我们特别不使用核心缓存API来保存有关可用更新的提取数据。至关重要的是,仅在成功获取新的可用更新数据后填充缓存时,才清除该缓存。核心缓存API的使用会导致各种潜在的问题,这些问题将导致尝试一直获取可用的更新数据,包括网站是否定义了“最小缓存生存期”(最小和最大),或网站使用内存缓存或其他采用易失性缓存的可插拔缓存系统。

Update Manager模块仍使用{cache_update}表,但是不是使用cache_set()cache_get()和来代替,而是使用cache_clear_all()私有帮助器函数来实现这些相同的基本任务,但要确保不会过早清除缓存,并且始终将数据存储在数据库,即使正在使用memcache或另一个缓存后端。

Update Manager具有必要的特定需求,因为尝试过于频繁地获取更新信息会导致Drupal.org服务器出现问题,因为Update Manager可能会从任何运行Drupal的站点获取更新信息。

在您的情况下,您可以将其[module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]用作单个缓存容器存储的缓存ID。如果您需要删除实体的所有条目,则可以使用以下代码。

cache_clear_all("{$module}__{$entity_type}__{$entity_id}__", $bin, TRUE);

如果$module在清除缓存时无法获取要分配的值,或者要独立于要缓存数据的模块删除缓存条目,则可以使用其他缓存ID,例如[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from][entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]cache_clear_all()删除所有具有缓存ID的缓存条目,该缓存ID以作为参数传递的字符串开头,为$wildcardis TRUE,而缓存ID为not '*'。在这种情况下,将使用以下代码清除缓存。

cache_clear_all("{$entity_type}__{$entity_id}__", $bin, TRUE);

8

我想不出一个很好的理由为什么手动删除条目会导致问题。当然,这假设您正在使用MySQL作为特定缓存的后端。尽管我认为这适用于任何其他类型的缓存后端,但是清除的方法不一定是数据库查询。

如果以核心更新模块为例,它会绕过cache_*功能并手动清除其缓存:

function _update_cache_clear($cid = NULL, $wildcard = FALSE) {
  if (empty($cid)) {
    db_delete('cache_update')
      // Clear everything except fetch task information because these are used
      // to ensure that the fetch task queue items are not added multiple times.
      ->condition('cid', 'fetch_task::%', 'NOT LIKE')
      ->execute();
  }
  else {
    $query = db_delete('cache_update');
    if ($wildcard) {
      $query->condition('cid', $cid . '%', 'LIKE');
    }
    else {
      $query->condition('cid', $cid);
    }
    $query->execute();
  }
}

我一直认为“如果对核心足够好,对我也足够好” :)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.