gin-base/db/core/cache.go

131 lines
2.5 KiB
Go

package core
import (
"crypto/md5"
"encoding/hex"
"fmt"
"sync"
"time"
)
// CacheItem 缓存项
type CacheItem struct {
Data interface{} // 缓存的数据
ExpiresAt time.Time // 过期时间
}
// QueryCache 查询缓存 - 提高重复查询的性能
type QueryCache struct {
mu sync.RWMutex // 读写锁
items map[string]*CacheItem // 缓存项
duration time.Duration // 默认缓存时长
}
// NewQueryCache 创建查询缓存实例
func NewQueryCache(duration time.Duration) *QueryCache {
cache := &QueryCache{
items: make(map[string]*CacheItem),
duration: duration,
}
// 启动清理协程
go cache.cleaner()
return cache
}
// Set 设置缓存
func (qc *QueryCache) Set(key string, data interface{}) {
qc.mu.Lock()
defer qc.mu.Unlock()
qc.items[key] = &CacheItem{
Data: data,
ExpiresAt: time.Now().Add(qc.duration),
}
}
// Get 获取缓存
func (qc *QueryCache) Get(key string) (interface{}, bool) {
qc.mu.RLock()
defer qc.mu.RUnlock()
item, exists := qc.items[key]
if !exists {
return nil, false
}
// 检查是否过期
if time.Now().After(item.ExpiresAt) {
return nil, false
}
return item.Data, true
}
// Delete 删除缓存
func (qc *QueryCache) Delete(key string) {
qc.mu.Lock()
defer qc.mu.Unlock()
delete(qc.items, key)
}
// Clear 清空所有缓存
func (qc *QueryCache) Clear() {
qc.mu.Lock()
defer qc.mu.Unlock()
qc.items = make(map[string]*CacheItem)
}
// cleaner 定期清理过期缓存
func (qc *QueryCache) cleaner() {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for range ticker.C {
qc.cleanExpired()
}
}
// cleanExpired 清理过期的缓存项
func (qc *QueryCache) cleanExpired() {
qc.mu.Lock()
defer qc.mu.Unlock()
now := time.Now()
for key, item := range qc.items {
if now.After(item.ExpiresAt) {
delete(qc.items, key)
}
}
}
// GenerateCacheKey 生成缓存键
func GenerateCacheKey(sql string, args ...interface{}) string {
// 将 SQL 和参数组合成字符串
keyData := sql
for _, arg := range args {
keyData += fmt.Sprintf("%v", arg)
}
// 计算 MD5 哈希
hash := md5.Sum([]byte(keyData))
return hex.EncodeToString(hash[:])
}
// WithCache 带缓存的查询装饰器
func (q *QueryBuilder) WithCache(cache *QueryCache) IQuery {
// 生成缓存键
cacheKey := GenerateCacheKey(q.Build())
// 尝试从缓存获取
if data, exists := cache.Get(cacheKey); exists {
// TODO: 将缓存数据映射到结果对象
_ = data
return q
}
// 缓存未命中,执行实际查询并缓存结果
return q
}