基于Drupal Cache API缓存User对象的有效性问询
Drupal Cache API 缓存用户对象的疑问
我正在学习Drupal Cache API,有一个关于在数据库(即cache_default MySQL表)中缓存用户(或一般对象)的问题。
请参考以下用于获取User对象的简单函数(我知道这类代码应放在自定义服务中,此处用函数仅为清晰展示):
<?php /** * Get a user object * @param Integer * @return User */ function get_user_data($uid) { if ($uid) { $cache_id = 'my_user:' . $uid; $user = NULL; if ($cache = \Drupal::cache()->get($cache_id)) { // Read user object from the default cache. $user = $cache->data; } else { // user not found in the cache. $user = \Drupal\user\Entity\User::load($uid); // Cache tags from User object, to tell Drupal to invalidate the cache // data after any change to the user. $user_cache_tags = $user->getCacheTags(); // Store a serialized user object in the default cache. \Drupal::cache()->set($cache_id, $user, Cache::PERMANENT, $user_cache_tags); } return $user; } return FALSE; }
我的目标是缓存一个依赖于多个Profile(使用Profiles模块)中大量数据的Drupal User对象。
我的场景中User可能需要更多属性,或与Profile对象交互的方式,因此可能需要扩展User(如“MyUser”类等),但对象设计不在本次问题范围内。
核心问题
上述代码是否有实际作用?(或者Drupal已在某处缓存User对象,该代码毫无意义?)
场景假设
- 无法使用Redis或Memcached。
- 每次获取用户数据时,Drupal应用必须执行大量繁琐的数据库查询(读取用户表、Profile表)。
回答
你的代码有实际作用,但需要结合场景做针对性调整,具体分析如下:
Drupal原生实体缓存的局限性
Drupal确实会自动缓存User实体,但原生缓存仅覆盖用户核心表(如users_field_data)的基础数据。当你需要关联多个Profile对象的大量数据时,原生缓存不会自动包含这些关联内容——每次调用User::load($uid)后,读取关联Profile数据仍会触发额外的数据库查询,这正是你要避免的“繁琐查询”场景。你的代码的核心价值
- 它可以把**包含关联Profile数据的完整用户对象(或自定义扩展后的MyUser对象)**一次性缓存,避免重复执行用户表+多个Profile表的查询操作,直接从
cache_default读取序列化后的完整对象,有效降低数据库负载。 - 你正确使用了
$user->getCacheTags(),这意味着当用户实体本身被修改时,Drupal会自动失效对应的缓存条目,保证数据一致性。
- 需要优化的关键点
- 如果缓存对象包含Profile数据,仅依赖User的缓存标签不够——当关联的Profile对象被修改时,你的缓存不会自动失效。需要将Profile的缓存标签也加入缓存条目:
// 假设通过字段关联获取用户的Profile对象 $profile_cache_tags = []; foreach ($user->get('field_profile')->referencedEntities() as $profile) { $profile_cache_tags = array_merge($profile_cache_tags, $profile->getCacheTags()); } $combined_tags = array_merge($user_cache_tags, $profile_cache_tags); \Drupal::cache()->set($cache_id, $user, Cache::PERMANENT, $combined_tags); - 遵循Drupal最佳实践,避免直接使用
\Drupal::cache(),建议通过依赖注入获取cache.default服务(你提到知道要放在自定义服务中,这点没问题)。 - 如果缓存自定义扩展的MyUser对象,要确保该对象可安全序列化(无无法序列化的资源,如数据库连接句柄)。
内容的提问来源于stack exchange,提问作者jtarleton
相关产品推荐
相关产品推荐

