Version: 0.3.0.dev.260212
refactor: ♻️ 基于 gorm 钩子实现自动缓存失效机制,再也不用牵一发而动全身写删缓存逻辑了~ - 通过 gorm hook 监听 MySQL 数据变更 🧩 - 自动删除对应表相关缓存,实现缓存失效自动化 🔄 - 移除原本写在 sv 层的手动删缓存逻辑 🧹 - 解耦业务逻辑与缓存控制,结构更加清晰 ✅ fix: 🐛 修复将任务类加入日程接口的时间字段遗漏问题 - 由于前版本 MySQL 表结构更新 - 漏写插入起始时间字段逻辑,导致500报错,现已补充 ⏱️ fix: 🐛 修复获取最近已完成任务列表接口的多个问题 - 移除不应存在的幂等键 🔁 - 修复“一个event输出多次”的问题(原因出自 dto 转换函数) 🔧 undo: ⚠️ 删除任务类接口未处理已安排任务块的解除逻辑 - 当前删除任务类时,未解除已被安排的任务块 - 该逻辑存在缺陷,计划在后续版本内修复 🛠️
This commit is contained in:
103
backend/middleware/cache_deleter.go
Normal file
103
backend/middleware/cache_deleter.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"reflect"
|
||||
|
||||
"github.com/LoveLosita/smartflow/backend/dao"
|
||||
"github.com/LoveLosita/smartflow/backend/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GormCachePlugin struct {
|
||||
cacheDAO *dao.CacheDAO
|
||||
}
|
||||
|
||||
func NewGormCachePlugin(dao *dao.CacheDAO) *GormCachePlugin {
|
||||
return &GormCachePlugin{
|
||||
cacheDAO: dao,
|
||||
}
|
||||
}
|
||||
|
||||
// Name 插件名称
|
||||
func (p *GormCachePlugin) Name() string {
|
||||
return "GormCachePlugin"
|
||||
}
|
||||
|
||||
// Initialize 注册 GORM 钩子
|
||||
func (p *GormCachePlugin) Initialize(db *gorm.DB) error {
|
||||
// 在增、删、改成功后,统一触发清理逻辑
|
||||
_ = db.Callback().Create().After("gorm:create").Register("clear_related_cache_after_create", p.afterWrite)
|
||||
_ = db.Callback().Update().After("gorm:update").Register("clear_related_cache_after_update", p.afterWrite)
|
||||
_ = db.Callback().Delete().After("gorm:delete").Register("clear_related_cache_after_delete", p.afterWrite)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GormCachePlugin) afterWrite(db *gorm.DB) {
|
||||
if db.Error != nil || db.Statement.Schema == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取 Model 的真实值(剥掉所有指针)
|
||||
val := reflect.Indirect(reflect.ValueOf(db.Statement.Model))
|
||||
|
||||
// 如果是切片,拿切片里元素的类型
|
||||
if val.Kind() == reflect.Slice {
|
||||
if val.Len() > 0 {
|
||||
p.dispatchCacheLogic(val.Index(0).Interface(), db)
|
||||
}
|
||||
} else {
|
||||
p.dispatchCacheLogic(val.Interface(), db)
|
||||
}
|
||||
}
|
||||
|
||||
// 根据不同的 Model 类型,调用不同的缓存失效逻辑
|
||||
func (p *GormCachePlugin) dispatchCacheLogic(modelObj interface{}, db *gorm.DB) {
|
||||
switch m := modelObj.(type) {
|
||||
case model.Schedule:
|
||||
// 无论传的是 &s, s, 还是 &[]s,剥开后都是 model.Schedule
|
||||
p.invalidScheduleCache(m.UserID, m.Week)
|
||||
case model.TaskClass:
|
||||
p.invalidTaskClassCache(*m.UserID)
|
||||
case model.Task:
|
||||
p.invalidTaskCache(m.UserID)
|
||||
default:
|
||||
// 只有真正没定义的模型才会到这里
|
||||
log.Printf("[GORM-Cache] No logic defined for model: %T", modelObj)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GormCachePlugin) invalidScheduleCache(userID int, week int) {
|
||||
if userID == 0 || week == 0 {
|
||||
return
|
||||
}
|
||||
// 3. 异步执行,不阻塞主业务事务
|
||||
go func() {
|
||||
// 这里调用你的 CacheDAO 删缓存
|
||||
_ = p.cacheDAO.DeleteUserWeeklyScheduleFromCache(context.Background(), userID, week)
|
||||
_ = p.cacheDAO.DeleteUserTodayScheduleFromCache(context.Background(), userID) // 同时删当天的缓存,确保数据一致
|
||||
_ = p.cacheDAO.DeleteUserRecentCompletedSchedulesFromCache(context.Background(), userID) // 同时删最近完成的缓存,确保数据一致
|
||||
log.Printf("[GORM-Cache] Invalidated cache for user %d, week %d", userID, week)
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *GormCachePlugin) invalidTaskClassCache(userID int) {
|
||||
if userID == 0 {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
_ = p.cacheDAO.DeleteTaskClassList(context.Background(), userID)
|
||||
log.Printf("[GORM-Cache] Invalidated task class list cache for user %d", userID)
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *GormCachePlugin) invalidTaskCache(userID int) {
|
||||
if userID == 0 {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
_ = p.cacheDAO.DeleteUserTasksFromCache(context.Background(), userID)
|
||||
log.Printf("[GORM-Cache] Invalidated task list cache for user %d", userID)
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user