cache

package
v0.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 7 Imported by: 0

README

cache 包 — 缓存抽象

所属层级: Infrastructure Layer
设计理念: 统一接口,Cache-Aside 模式
设计灵感: Spring Cache + Caffeine

概述

cache 包提供统一的缓存操作接口抽象,支持不同的缓存实现(如 Redis、内存缓存、Caffeine 本地缓存)无缝替换。核心设计模式包括 Cache-Aside(缓存旁路)模式,通过 Getter 函数实现缓存未命中时的数据加载。

核心功能
功能 说明
统一接口 Cache 接口定义标准缓存操作
Cache-Aside 模式 缓存未命中时自动从数据源加载
内存缓存 MemoryCache 适用于测试和轻量场景
高性能本地缓存 CaffeineCache 支持 LRU 淘汰 + TTL
批量操作 支持批量获取、设置、删除
TTL 过期 支持为每个缓存项设置独立的过期时间

核心接口

Cache 接口
type Cache interface {
    Get(ctx context.Context, key string) (any, error)
    Set(ctx context.Context, key string, value any, ttl time.Duration) error
    Del(ctx context.Context, keys ...string) error
    Exists(ctx context.Context, key string) (bool, error)
    TTL(ctx context.Context, key string) (time.Duration, error)
    Close() error
}
方法说明
方法 说明
Get 获取指定键的缓存值,键不存在返回 ErrNotFound,已过期返回 ErrCacheMiss
Set 设置缓存键值,可指定 TTL 过期时间。ttl <= 0 表示永不过期
Del 删除一个或多个缓存键
Exists 检查键是否存在(已过期的键视为不存在)
TTL 获取键的剩余过期时间。未设置过期时间返回 0,不存在返回 ErrNotFound
Close 关闭缓存连接并释放资源
Getter — 数据加载函数
type Getter func(ctx context.Context, key string) (any, error)

用于 Cache-Aside(缓存旁路)模式:当缓存未命中时,通过 Getter 从数据源加载数据并回填缓存。

错误 sentinel
var (
    ErrNotFound  = errors.New("cache: key not found")
    ErrCacheMiss = errors.New("cache: key expired or not found")
)
错误 说明
ErrNotFound 缓存键不存在(从未设置)
ErrCacheMiss 缓存键已过期或未命中

快速开始

创建内存缓存
package main

import (
    "context"
    "time"
    "github.com/xudefa/enhance/cache"
)

func main() {
    c := cache.NewMemoryCache()
    ctx := context.Background()

    // 设置缓存,5 分钟过期
    err := c.Set(ctx, "user:1", userData, 5*time.Minute)

    // 获取缓存
    val, err := c.Get(ctx, "user:1")
}
Cache-Aside 模式
val, err := c.GetWithGetter(ctx, "user:1", func(ctx context.Context, key string) (any, error) {
    // 从数据库加载
    var user User
    db.First(&user, 1)
    return user, nil
})

API 参考

MemoryCache — 内存缓存实现

基于 sync.RWMutexmap[string]cacheItem 的并发安全内存缓存实现,支持 TTL 过期和延迟清理。

创建
cache := cache.NewMemoryCache()
使用场景
  • 测试环境
  • 轻量级应用
  • 缓存原型开发
扩展方法
方法 说明
GetWithGetter Cache-Aside 模式:缓存未命中时从数据源加载
GetMulti 批量获取多个键的缓存值
SetMulti 批量设置多个缓存键值
DeleteMulti 批量删除多个缓存键
Clear 清空所有缓存
CaffeineCache — 高性能本地缓存

基于 LRU(最近最少使用)淘汰策略的高性能本地缓存实现,适用于需要控制内存使用量的场景。

创建
// 使用默认配置(最大 1000 项,默认 TTL 5 分钟)
cache := cache.NewCaffeineCache()

// 自定义配置
cache := cache.NewCaffeineCache(
    cache.WithCaffeineMaxSize(5000),
    cache.WithCaffeineDefaultTTL(10*time.Minute),
)
特性
特性 说明
LRU 淘汰 当缓存达到最大容量时,自动淘汰最久未使用的项
TTL 支持 支持为每个缓存项设置独立的过期时间
并发安全 使用 sync.RWMutex 保护并发访问
O(1) 操作 基于 map + 双向链表实现,Get/Set 都是 O(1) 时间复杂度
使用示例
c := cache.NewCaffeineCache(cache.WithMaxSize(1000))
ctx := context.Background()

// 设置缓存
_ = c.Set(ctx, "user:1", userData, 5*time.Minute)

// 获取缓存(会更新 LRU 位置)
val, err := c.Get(ctx, "user:1")

// 查看缓存统计
stats := c.Stats()

使用示例

基础操作
c := cache.NewMemoryCache()
ctx := context.Background()

// 设置缓存,5 分钟过期
err := c.Set(ctx, "user:1", userData, 5*time.Minute)

// 获取缓存
val, err := c.Get(ctx, "user:1")
if errors.Is(err, cache.ErrNotFound) {
    // 键不存在
}
if errors.Is(err, cache.ErrCacheMiss) {
    // 键已过期
}

// 检查是否存在
exists, _ := c.Exists(ctx, "user:1")

// 获取剩余 TTL
ttl, _ := c.TTL(ctx, "user:1")

// 批量操作
items := map[string]any{"a": 1, "b": 2}
_ = c.SetMulti(ctx, items, time.Minute)
result, _ := c.GetMulti(ctx, []string{"a", "b"})
_ = c.DeleteMulti(ctx, []string{"a", "b"})

// 清空
_ = c.Clear(ctx)
Cache-Aside 模式
val, err := c.GetWithGetter(ctx, "user:1", func(ctx context.Context, key string) (any, error) {
    // 从数据库加载
    var user User
    db.First(&user, 1)
    return user, nil
})
与依赖注入集成
// 注册为 Bean
container.Register(
    reflect.TypeOf(&cache.MemoryCache{}),
    core.Bean(cache.NewMemoryCache()),
    core.Singleton(),
)

// 注入使用
type UserService struct {
    Cache cache.Cache `inject:"cache"`
}

最佳实践

1. 使用 Cache-Aside 模式简化缓存逻辑
// ✅ 推荐:使用 GetWithGetter 自动回填缓存
val, err := c.GetWithGetter(ctx, "user:1", func(ctx context.Context, key string) (any, error) {
    return db.GetUser(id)
})

// ⚠️ 不推荐:手动实现缓存逻辑
val, err := c.Get(ctx, key)
if err == cache.ErrNotFound {
    val, err = db.GetUser(id)
    if err == nil {
        c.Set(ctx, key, val, ttl)
    }
}
2. 合理设置 TTL
// ✅ 推荐:根据数据更新频率设置合理的 TTL
c.Set(ctx, "user:1", userData, 5*time.Minute)    // 用户数据 5 分钟
c.Set(ctx, "config:app", config, 1*time.Hour)     // 配置数据 1 小时

// ⚠️ 不推荐:所有数据使用相同 TTL
c.Set(ctx, key, value, 10*time.Minute)
3. 使用 CaffeineCache 控制内存使用
// ✅ 推荐:设置最大缓存大小
c := cache.NewCaffeineCache(
    cache.WithCaffeineMaxSize(5000),
    cache.WithCaffeineDefaultTTL(10*time.Minute),
)

// ⚠️ 不推荐:不限制缓存大小,可能导致内存溢出
c := cache.NewMemoryCache()
4. 批量操作提升性能
// ✅ 推荐:使用批量操作
items := map[string]any{"user:1": u1, "user:2": u2}
c.SetMulti(ctx, items, time.Minute)

// ⚠️ 不推荐:循环单个设置
for key, value := range items {
    c.Set(ctx, key, value, time.Minute)
}
5. 与依赖注入集成
// ✅ 推荐:将缓存注册为 Bean
container.Register(
    reflect.TypeOf(&cache.MemoryCache{}),
    core.Bean(cache.NewMemoryCache()),
    core.Singleton(),
)

// 注入使用
type UserService struct {
    Cache cache.Cache `inject:"cache"`
}

Documentation

Overview

Package cache 提供类似 Caffeine 的本地缓存实现,采用 LRU 淘汰策略。

CaffeineCache 是一个实现 Cache 接口的高性能本地缓存。 当缓存达到最大容量时,它提供 LRU(最近最少使用)淘汰策略, 并为单个缓存条目提供 TTL(生存时间)支持。

用法:

cache := cache.NewCaffeineCache(
	cache.WithCaffeineMaxSize(1000),
	cache.WithCaffeineDefaultTTL(5*time.Minute),
)

cache.Set(ctx, "key", "value", 10*time.Minute)
value, err := cache.Get(ctx, "key")

Package cache 提供缓存抽象层,用于 enhance 框架。

该模块提供多种缓存策略实现,包括 LRU 缓存和 Caffeine 缓存。 参考 Spring Cache 的设计理念,提供统一的缓存抽象接口。

架构设计

  • Cache: 缓存操作接口
  • Getter: 缓存获取器,支持缓存穿透保护
  • Builder: 缓存构建器,支持链式配置
  • LRUCache: LRU(Least Recently Used)缓存实现
  • ShardedLRUCache: 分片 LRU 缓存,适合高并发场景
  • CaffeineCache: 类似 Caffeine 的高性能缓存实现

支持的缓存策略

  • LRU 缓存: 基于最近最少使用算法的缓存实现
  • Caffeine 缓存: 类似 Java Caffeine 的高性能缓存实现
  • 分片缓存: 支持并发安全的分片 LRU 缓存

使用方式

使用 LRU 缓存:

cache := cache.NewLRUCache(1000) // 最大 1000 个条目
cache.Set(context.Background(), "key", "value", 5*time.Minute)
value, err := cache.Get(context.Background(), "key")

使用缓存构建器:

cache := cache.NewMemoryCacheBuilder().
    InitialCapacity(1000).
    TTL(5*time.Minute).
    Build()

使用缓存获取器(带穿透保护):

getter := cache.NewGetter(func(key string) (any, error) {
    // 从数据库加载
    return loadFromDB(key)
})
value, err := getter.Get("key")

Package cache 提供缓存抽象层,用于 enhance 框架。

Package cache 提供缓存抽象层,用于 enhance 框架。

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound 缓存键不存在。
	ErrNotFound = errors.New("cache: key not found")
	// ErrCacheMiss 缓存键已过期或不存在。
	ErrCacheMiss = errors.New("cache: key expired or not found")
)

Functions

func NewCaffeineCache

func NewCaffeineCache(opts ...CaffeineOption) *caffeineCache

NewCaffeineCache 创建一个新的类 Caffeine 本地缓存,采用 LRU 淘汰策略。

该缓存使用 map 实现 O(1) 查找,使用双向链表实现 O(1) LRU 跟踪。默认配置:

  • 最大容量:1000 个条目
  • 默认 TTL:5 分钟

Types

type Cache

type Cache interface {
	// Get 获取指定键的缓存值,不存在返回 ErrNotFound。
	Get(ctx context.Context, key string) (any, error)

	// Set 设置缓存键值,ttl<=0 表示永不过期。
	Set(ctx context.Context, key string, value any, ttl time.Duration) error

	// Del 删除指定的缓存键。
	Del(ctx context.Context, keys ...string) error

	// Exists 检查键是否存在且未过期。
	Exists(ctx context.Context, key string) (bool, error)

	// TTL 获取键的剩余过期时间。
	TTL(ctx context.Context, key string) (time.Duration, error)

	// Close 关闭缓存连接并释放资源。
	Close() error
}

Cache 缓存操作接口。

所有缓存实现都应该实现此接口, 以便与 enhance 的依赖注入系统集成。

type CacheConfig

type CacheConfig struct {
	Enabled      bool          // 是否启用缓存
	DefaultTTL   time.Duration // 默认TTL
	MaxSize      int           // 最大缓存项数
	KeyPrefix    string        // 键前缀
	StatsEnabled bool          // 是否启用统计
}

CacheConfig 缓存配置

func DefaultCacheConfig

func DefaultCacheConfig() *CacheConfig

DefaultCacheConfig 返回默认缓存配置

func (*CacheConfig) ApplyOptions

func (c *CacheConfig) ApplyOptions(opts []CacheOption)

ApplyOptions 应用配置选项

type CacheHelper

type CacheHelper struct {
	// contains filtered or unexported fields
}

CacheHelper 缓存辅助工具,简化常见缓存操作

func NewCacheHelper

func NewCacheHelper(cache Cache) *CacheHelper

NewCacheHelper 创建缓存辅助工具

func (*CacheHelper) Clear

func (h *CacheHelper) Clear(ctx context.Context) error

Clear 清空所有缓存

func (*CacheHelper) Exists

func (h *CacheHelper) Exists(ctx context.Context, key string) (bool, error)

Exists 检查键是否存在

func (*CacheHelper) Get

func (h *CacheHelper) Get(ctx context.Context, key string) (any, error)

Get 获取缓存值,调用方需自行类型断言

func (*CacheHelper) GetOrSet

func (h *CacheHelper) GetOrSet(ctx context.Context, key string, fn func() (any, error), ttl time.Duration) (any, error)

GetOrSet 获取缓存值,如果不存在则使用提供的函数获取并缓存

func (*CacheHelper) Invalidate

func (h *CacheHelper) Invalidate(ctx context.Context, key string) error

Invalidate 使缓存失效

func (*CacheHelper) InvalidateAll

func (h *CacheHelper) InvalidateAll(ctx context.Context, keys ...string) error

InvalidateAll 使所有指定键的缓存失效

func (*CacheHelper) Set

func (h *CacheHelper) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set 设置缓存值

func (*CacheHelper) TTL

func (h *CacheHelper) TTL(ctx context.Context, key string) (time.Duration, error)

TTL 获取键的剩余过期时间

type CacheOption

type CacheOption func(*CacheConfig)

CacheOption 缓存配置选项

func WithCacheEnabled

func WithCacheEnabled(enabled bool) CacheOption

WithCacheEnabled 设置是否启用缓存

func WithDefaultTTL

func WithDefaultTTL(ttl time.Duration) CacheOption

WithDefaultTTL 设置默认TTL

func WithKeyPrefix

func WithKeyPrefix(prefix string) CacheOption

WithKeyPrefix 设置键前缀

func WithMaxSize

func WithMaxSize(size int) CacheOption

WithMaxSize 设置最大缓存项数

func WithStatsEnabled

func WithStatsEnabled(enabled bool) CacheOption

WithStatsEnabled 设置是否启用统计

type CacheTemplate

type CacheTemplate struct {
	// contains filtered or unexported fields
}

CacheTemplate 缓存模板,提供常用的缓存操作模板

func NewCacheTemplate

func NewCacheTemplate(cache Cache, prefix string) *CacheTemplate

NewCacheTemplate 创建缓存模板

func (*CacheTemplate) Del

func (t *CacheTemplate) Del(ctx context.Context, key string) error

Del 删除缓存键

func (*CacheTemplate) Exists

func (t *CacheTemplate) Exists(ctx context.Context, key string) (bool, error)

Exists 检查键是否存在

func (*CacheTemplate) Get

func (t *CacheTemplate) Get(ctx context.Context, key string) (any, error)

Get 获取缓存值

func (*CacheTemplate) GetOrSet

func (t *CacheTemplate) GetOrSet(ctx context.Context, key string, fn func() (any, error), ttl time.Duration) (any, error)

GetOrSet 获取或设置缓存值

func (*CacheTemplate) Key

func (t *CacheTemplate) Key(key string) string

Key 生成带前缀的键

func (*CacheTemplate) Set

func (t *CacheTemplate) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set 设置缓存值

func (*CacheTemplate) TTL

func (t *CacheTemplate) TTL(ctx context.Context, key string) (time.Duration, error)

TTL 获取键的剩余过期时间

type CaffeineOption

type CaffeineOption func(*caffeineCache)

CaffeineOption configures the Caffeine cache.

func WithCaffeineDefaultTTL

func WithCaffeineDefaultTTL(ttl time.Duration) CaffeineOption

WithCaffeineDefaultTTL 设置缓存条目的默认 TTL。 当调用 Set() 且 ttl <= 0 时使用此 TTL。

func WithCaffeineMaxSize

func WithCaffeineMaxSize(maxSize int) CaffeineOption

WithCaffeineMaxSize 设置缓存中的最大条目数。 当缓存达到此大小时,最近最少使用的条目将被淘汰。

type Getter

type Getter func(ctx context.Context, key string) (any, error)

Getter 缓存旁路模式的值加载函数。

在缓存未命中时调用,从数据源加载值。 返回 nil 值不会被缓存。

type LRUCache

type LRUCache struct {
	// contains filtered or unexported fields
}

LRUCache LRU(最近最少使用)缓存实现。

基于双向链表和哈希表实现 O(1) 时间复杂度的缓存操作。 支持 TTL 过期淘汰和容量限制淘汰。 LRUCache 是并发安全的,所有操作都通过互斥锁保护。

func NewLRUCache

func NewLRUCache(capacity int, opts ...LRUOption) *LRUCache

NewLRUCache 创建 LRU 缓存。

参数:

  • capacity: 缓存容量,必须大于 0(<=0 时使用默认值 100)
  • opts: 可选配置项

返回:

  • *LRUCache: LRU 缓存实例

func (*LRUCache) Clear

func (c *LRUCache) Clear()

Clear 清空缓存。

func (*LRUCache) Close

func (c *LRUCache) Close() error

Close 关闭缓存并清空所有数据。

func (*LRUCache) Del

func (c *LRUCache) Del(ctx context.Context, keys ...string) error

Del 删除缓存项。

参数:

  • ctx: 上下文(保留用于接口一致性,当前未使用)
  • keys: 要删除的缓存键列表

func (*LRUCache) Exists

func (c *LRUCache) Exists(ctx context.Context, key string) (bool, error)

Exists 检查键是否存在且未过期。

参数:

  • ctx: 上下文(保留用于接口一致性,当前未使用)
  • key: 缓存键

返回值:

  • bool: 键存在且未过期返回 true
  • error: 始终返回 nil

func (*LRUCache) Get

func (c *LRUCache) Get(ctx context.Context, key string) (any, error)

Get 获取缓存值。

如果键不存在或已过期,返回 ErrNotFound。 命中缓存时会将该键移到链表前端(标记为最近使用)。

参数:

  • ctx: 上下文(保留用于接口一致性,当前未使用)
  • key: 缓存键

返回值:

  • any: 缓存值
  • error: 键不存在或已过期时返回 ErrNotFound

func (*LRUCache) Len

func (c *LRUCache) Len() int

Len 返回缓存项数量。

func (*LRUCache) Set

func (c *LRUCache) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set 设置缓存值。

如果键已存在,更新值并刷新过期时间。 如果超出容量,淘汰最久未使用的项。

参数:

  • ctx: 上下文(保留用于接口一致性,当前未使用)
  • key: 缓存键
  • value: 缓存值
  • ttl: 过期时间(<=0 表示永不过期)

func (*LRUCache) TTL

func (c *LRUCache) TTL(ctx context.Context, key string) (time.Duration, error)

TTL 获取键的剩余过期时间。

参数:

  • ctx: 上下文(保留用于接口一致性,当前未使用)
  • key: 缓存键

返回值:

  • time.Duration: 剩余过期时间(永不过期时返回 -1)
  • error: 键不存在或已过期时返回 ErrNotFound

type LRUOption

type LRUOption func(*LRUCache)

LRUOption LRU 缓存选项函数。

func WithEvictCallback

func WithEvictCallback(fn func(key string, value any)) LRUOption

WithEvictCallback 设置淘汰回调函数。

当缓存项因容量限制被淘汰时调用此回调。 可用于记录日志、清理资源等场景。

func WithTTL added in v0.0.4

func WithTTL(ttl time.Duration) LRUOption

WithTTL 设置默认 TTL。

当 Set 传入 ttl <= 0 时使用该默认值。

type MemoryCacheBuilder

type MemoryCacheBuilder struct {
	// contains filtered or unexported fields
}

MemoryCacheBuilder 内存缓存构建器,支持链式配置

func NewMemoryCacheBuilder

func NewMemoryCacheBuilder() *MemoryCacheBuilder

NewMemoryCacheBuilder 创建内存缓存构建器

func (*MemoryCacheBuilder) Build

func (b *MemoryCacheBuilder) Build() Cache

Build 构建 LRU 缓存

func (*MemoryCacheBuilder) InitialCapacity

func (b *MemoryCacheBuilder) InitialCapacity(capacity int) *MemoryCacheBuilder

InitialCapacity 设置初始容量

func (*MemoryCacheBuilder) MustBuild

func (b *MemoryCacheBuilder) MustBuild() Cache

MustBuild 构建 LRU 缓存

func (*MemoryCacheBuilder) TTL

TTL 设置默认过期时间

type ShardedLRUCache

type ShardedLRUCache struct {
	// contains filtered or unexported fields
}

ShardedLRUCache 分片 LRU 缓存实现。

将全局锁拆分为多个分段锁,提升高并发场景下的性能。 每个分片独立维护自己的 LRU 链表和哈希表。

func NewShardedLRUCache

func NewShardedLRUCache(capacity int, shardCount int, opts ...LRUOption) *ShardedLRUCache

NewShardedLRUCache 创建分片 LRU 缓存

参数:

  • capacity: 总容量,将平均分配到各分片
  • shardCount: 分片数量,建议为 2 的幂次(如 16, 32, 64)
  • opts: 可选配置项

返回:

  • *ShardedLRUCache: 分片 LRU 缓存实例

func (*ShardedLRUCache) Clear

func (c *ShardedLRUCache) Clear()

Clear 清空缓存

func (*ShardedLRUCache) Close

func (c *ShardedLRUCache) Close() error

Close 关闭缓存

func (*ShardedLRUCache) Del

func (c *ShardedLRUCache) Del(ctx context.Context, keys ...string) error

Del 删除缓存项

func (*ShardedLRUCache) Exists

func (c *ShardedLRUCache) Exists(ctx context.Context, key string) (bool, error)

Exists 检查键是否存在且未过期

func (*ShardedLRUCache) Get

func (c *ShardedLRUCache) Get(ctx context.Context, key string) (any, error)

Get 获取缓存值

func (*ShardedLRUCache) Len

func (c *ShardedLRUCache) Len() int

Len 返回缓存项数量

func (*ShardedLRUCache) Set

func (c *ShardedLRUCache) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set 设置缓存值

func (*ShardedLRUCache) TTL

func (c *ShardedLRUCache) TTL(ctx context.Context, key string) (time.Duration, error)

TTL 获取键的剩余过期时间

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL