gin-base/db/core/cache.go

149 lines
2.9 KiB
Go

package core
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"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[:])
}
// deepCopy 深拷贝数据(使用 JSON 序列化/反序列化)
func deepCopy(src, dst interface{}) error {
// 序列化为 JSON
data, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("序列化失败:%w", err)
}
// 反序列化到目标
if err := json.Unmarshal(data, dst); err != nil {
return fmt.Errorf("反序列化失败:%w", err)
}
return nil
}
// WithCache 带缓存的查询装饰器
func (q *QueryBuilder) WithCache(cache *QueryCache) IQuery {
if cache == nil {
return q
}
// 设置缓存实例
q.cache = cache
q.useCache = true
// 生成缓存键(使用 SQL 和参数)
sqlStr, args := q.BuildSelect()
q.cacheKey = GenerateCacheKey(sqlStr, args...)
return q
}