package common import ( "context" "strings" "sync" "time" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) var ( cacheTTL time.Duration cacheTTLOnce sync.Once ) // CacheTTL returns the database query cache TTL from config func CacheTTL() time.Duration { cacheTTLOnce.Do(func() { cacheTTL = time.Duration(g.Cfg().MustGet(context.Background(), "database.cache.ttl", 60).Int()) * time.Second }) return cacheTTL } // CacheName 生成 dao 查询缓存名:统一以 "table@" 开头, // CacheClear 按表前缀精确清理的前提(gdb 缓存键 = "SelectCache:" + name) func CacheName(table, op string, params ...any) string { s := table + "@" + op for _, p := range params { s += "_" + gconv.String(p) } return s } // CacheClear 清理某表全部查询缓存,dao 写操作成功后必须调用(否则"库里已改、查询还是旧值")。 // gdb.DB 接口未暴露 Core.ClearCache,此处等价实现:遍历缓存键,删除 "SelectCache:@" 前缀条目。 func CacheClear(ctx context.Context, db gdb.DB, table string) { keys, err := db.GetCache().KeyStrings(ctx) if err != nil { g.Log().Warningf(ctx, "清理 %s 查询缓存失败(读取键): %v", table, err) return } prefix := "SelectCache:" + table + "@" var toRemove []any for _, k := range keys { if strings.HasPrefix(k, prefix) { toRemove = append(toRemove, k) } } if len(toRemove) > 0 { if err := db.GetCache().Removes(ctx, toRemove); err != nil { g.Log().Warningf(ctx, "清理 %s 查询缓存失败: %v", table, err) } } }