Database 皮肤:渲染流程中的缓存

针对 file_system=database 的前台 Liquid 渲染,按请求时序说明各层缓存的 Key 格式、存储内容、TTL、失效时机
皮肤安装 / OSS / 同步链路见 database-theme-flow.md;与 file 皮肤共用的装修数据缓存见 theme-decoration-and-liquid-rendering.md


一、渲染时缓存命中顺序

一次典型前台页面请求(非 checkout),database 皮肤相关缓存大致按以下顺序参与:

flowchart TB
    REQ[HTTP 请求] --> FETCH[HomeBaseController::fetch]
    FETCH --> CTX["Context->themeAssets<br/>(请求级内存)"]
    CTX --> RA["Redis themeAssets<br/>Hash 全量或命中"]
    RA -->|miss| DB1[(o_theme_asset 主库)]
    FETCH --> LAYOUT[读 layout liquid 文本]
    LAYOUT --> AST["磁盘 Liquid AST<br/>runtime/liquid/cache/{themeName}/"]
    FETCH --> TD[ThemesService::themeData]
    TD --> TS["Redis themeSections<br/>积木块列表"]
    TD --> TF["Redis themeFiles<br/>/config /sections /locales"]
    TD --> TV["Redis themeView<br/>视角列表"]
    TD --> TG["Redis themeGroupId<br/>组装修 obj→group_id"]
    RENDER[Liquid 渲染 TagSection 等] --> LC["Redis liquidcache:*<br/>HTML/CSS/JS 片段"]
    RENDER --> OSS[OSS public_url<br/>/assets 静态资源<br/>不走 Redis 读内容]

要点

  • Liquid 模板正文(layout / templates / sections / snippets)走 themeAssets → 请求内 Context->themeAssetsthemeFiles
  • themeFiles 在渲染中用于 按目录批量读小文件(config、locales、sections schema 解析),与 themeAssets 是两套 Redis Hash。
  • /assets 下 css/js/图片 存 OSS;Redis 里虽有整行 o_theme_asset JSON(含 public_url),但 不会把 OSS 文件内容载入缓存,URL 由 asset_url filter 拼出。

二、店铺级 Key 前缀

CacheKeyHelper::store() 返回 {storeId}:,例如店铺 12345 的前缀为 12345:

下文示例均假设 storeId = 12345themeId = 99


三、Database 专属:模板资产缓存

3.1 请求级内存 — Context->themeAssets

说明
写入时机HomeBaseController::fetch() 开头,file_system == database 且非 checkout
代码app("Context")->themeAssets = ThemeAssetService::getThemeAssetsByDatabase($themeId)
结构与 Redis themeAssets Hash 相同:field → JSON 字符串
生命周期单次 HTTP 请求;所有 OemsaasDatabase::readTemplateFile()getOneThemeAssetContent() 只读此数组

3.2 Redis Hash — themeAssets(渲染主路径)

Redis Key{storeId}:themeassets:theme_id:{themeId}
HelperCacheKeyHelper::themeAssets($themeId)
Hash Fieldmd5("{themeId}_{filePath}")filePath 形如 /layout/theme.liquid/sections/header.liquid
Helper(Field)CacheKeyHelper::themeAssetsFileKey($themeId, $filePath)
Valueo_theme_asset 整行 JSON(含 contentcontent_oss_bucketpublic_urlchecksum 等)
TTL1 天SysConst::ONE_DAY_SECONDS
填充Key 不存在时:ThemeAssetModelstore_id + theme_id 全表查主库 → hMSet + expire
读取getOneThemeAssetContent() 只取 JSON 里的 content 字段(liquid/json 文本);OSS 大文件 content 通常为空

Field 示例

Key:   12345:themeassets:theme_id:99
Field: md5("99_/layout/theme.liquid")  → 例如 a1b2c3...
Value: {"id":1,"theme_id":99,"folder":"/layout","file_name":"theme.liquid","content":"{% ... %}","public_url":"",...}

失效 / 更新

操作行为
API 新增 assetdel themeFilesthemeAssets(下次全量 key 过期后重建)
API 更新 assetthemeAssets key 已存在hSet 单 field 更新;并 del themeFiles
API 删除 assethDel 对应 field;del themeFiles
Key 不存在下次 getThemeAssetsByDatabase 从 DB 全量重建

排障:改 liquid 后前台仍旧内容 → 查 Redis key 是否仍在 TTL 内且 field 未更新;或强制 DEL 12345:themeassets:theme_id:99

3.3 Redis Hash — themeFiles(按目录,辅助路径)

Redis Key{storeId}:themes:{themeId}:files
HelperCacheKeyHelper::themeFiles($themeId)
Hash Field目录名,如 /config/sections/locales
Valuefolder 下所有 o_theme_asset 行的 JSON 数组
TTLKey 级 1 天(每次 hSetexpire
返回给调用方getContentsByFolder() 转为 file_name => content 映射(仅 content 列

渲染中的调用点(database 皮肤):

场景方法Folder
settings_schema.json / settings_data.jsonThemesService::getThemeConfigFromDatabase()/config
Section liquid 内 {% schema %} 解析ThemesService::getThemeSectionsConfigFromDatabase()/sections
前台语言包LangService/locales

themeAssets 的区别

themeAssetsthemeFiles
粒度单文件 field(md5 路径)整目录一个 field
渲染读 liquid 模板(主路径)否(除非走 getContentsByFolder)
含 OSS 行是(整行 JSON)是(但返回值只用 content)
更新策略增量 hSet / hDel任意 asset 变更 del 整个 Hash

四、Liquid 解析 AST — 本地磁盘

路径runtime/liquid/cache/{themeName}/
文件名md5(liquid 源码字符串)
内容序列化后的 Liquid AST(TagTemplate / TagSection / TagInclude 等)
TTL90 天3600 * 24 * 90
配置extend/liquidExtend/file/File.php

说明:database 与 file 皮肤共用;改 liquid 源码后若 AST 文件仍在,可能继续用旧 AST,直到源码 hash 变化或手动清目录。这与 Redis themeAssets 是独立一层。


五、装修数据缓存(database / file 共用)

渲染 TagGetBlocks / themeData 时会用到以下 Redis 缓存(不区分 file_system)。

5.1 themeSections — 页面积木块列表

Redis Key{storeId}:themes:{themeKey}:sections
HelperCacheKeyHelper::themeSections($themeKey)
themeKey默认主题非 preview 时用 default;否则为具体 themeId
Hash Field{route}{route}_{routeHandle};组装修时为 {route}:routeGroup:{groupId}
ValuesectionsFormat 之后的 blocks JSON 数组
TTL1 天
条件default=1 且非 preview 时写入

示例:

Key:   12345:themes:default:sections
Field: index
Field: product_my-handle
Field: index:routeGroup:42

5.2 themeData — 默认主题行缓存

Redis Key{storeId}:themes:{themeKey}:data
Valueo_store_theme 行 JSON(含 params 等)
TTL1 天
用途取默认主题信息;非每次 render 必 hit

5.3 themeView — 视角列表

Redis Keythemes_view:{storeId}{themeId}CacheKeyHelper::themeView
Valueo_theme_view 列表 JSON
TTL有数据 1 天;空列表 1 小时EMPTY_REDIS_HOLDER
用途ThemeViewService / LiquidCacheServiceviewId

5.4 themeGroupIdByObjIdAndType — 组装修 obj → group_id

Redis Keytheme_group_id:{storeId}{themeId}:{objId}:{objType}
Value整数 group_id
TTL1 天
用途商品/专辑页匹配装修分组

六、渲染结果片段缓存(HTML / CSS / JS)

LiquidCacheService 与 section 上 cached="true" 配合;themeIdviewId,database 与 file 一致。

6.1 Section 级 — liquidcache:*

类型Key 格式TTL
HTMLliquidcache:html:{storeId}{name}2 分钟(header 等)
CSSliquidcache:css:{storeId}{name}同上 +1s
JSliquidcache:js:{storeId}{name}同上 +1s

{name} 示例:99:USD:header 或带自定义 cache_key 后缀。

索引 ZSet:liquidcache:keys:{storeId}list,member 为上述 key,score 为过期时间戳。

6.2 首页整页 — home_index_cache:*

后缀Key 示例
htmlhome_index_cache:12345:{domainId}:99:{viewId}:USD:html_string
css...:style_sheet
js...:java_script

条件:非主域名、非主题编辑 Cookie、店铺配置开启等(见 LiquidCacheService::getIndexRenderCache)。

6.3 专辑详情页 — home_collection_detail_cache:*

home_collection_detail_cache:{storeId}:{domainId}:{themeId}:{viewId}:{collectionId}:{currency}:{page}:html_string

(另有 style_sheet / java_script 后缀。)


七、当前未启用 / 非渲染路径

Key状态说明
themeConfigs代码中已注释section schema 缓存曾计划启用,现每次走 getContentsByFolder('/sections')
themeDbData无引用CacheKeyHelper::themeDbData 仅定义,业务未使用
themeZipKey打包下载themeZip() 用,不参与前台 render
OSS 对象不走 Redis/assets 通过 public_url + CDN/OSS 直链

八、失效关系速查

业务操作建议清理 / 自动行为
ThemeTool PUT themeassetupdateAssetsCache 增量更新 themeAssets field + del themeFiles
新增 themeassetdel themeFilesthemeAssets 等 TTL 或手动 DEL
删除 themeassethDel themeAssets field + del themeFiles
settings_data.json触发 initThemeDataBySettingData;装修缓存见 ThemesServicedel themeData / themeSections
改 blocks / 设默认主题del themeData('default'), del themeSections('default')
改视角ThemeViewCacheService::delCache
改组装修ThemeRouteGroupCacheService::cleanCacheByObjIdAndType
改 liquid 仍见旧版themeAssets + 磁盘 AST 两层

九、与 file 皮肤差异(仅缓存层)

缓存层filedatabase
模板正文来源磁盘 public/theme/{name}/Redis themeAssets + DB
themeAssets / themeFiles一般不用渲染必用
Liquid AST 磁盘有(相同)
themeSections / 片段 HTML有(相同)
静态资源本地 /theme/.../assets/OSS URL(Redis 只存元数据)

十、代码索引

职责路径
预加载 themeAssetsapp/home/HomeBaseController.phpfetch()
themeAssets / themeFiles CRUD 缓存common/services/ThemeAssetService.php
DB 读模板extend/liquidExtend/fileSystem/OemsaasDatabase.php
Key 定义extend/helper/CacheKeyHelper.php
积木块 Rediscommon/services/ThemesService.phpgetThemeSectionsData
组装修 blockscommon/services/ThemeRouteGroupCacheService.php
视角common/services/ThemeViewCacheService.php
HTML 片段common/services/LiquidCacheService.php
AST 磁盘extend/liquidExtend/file/File.php

上级:database-theme-flow.md · README.md