Version: 0.3.0.dev.260212
refactor: ♻️ 基于 gorm 钩子实现自动缓存失效机制,再也不用牵一发而动全身写删缓存逻辑了~ - 通过 gorm hook 监听 MySQL 数据变更 🧩 - 自动删除对应表相关缓存,实现缓存失效自动化 🔄 - 移除原本写在 sv 层的手动删缓存逻辑 🧹 - 解耦业务逻辑与缓存控制,结构更加清晰 ✅ fix: 🐛 修复将任务类加入日程接口的时间字段遗漏问题 - 由于前版本 MySQL 表结构更新 - 漏写插入起始时间字段逻辑,导致500报错,现已补充 ⏱️ fix: 🐛 修复获取最近已完成任务列表接口的多个问题 - 移除不应存在的幂等键 🔁 - 修复“一个event输出多次”的问题(原因出自 dto 转换函数) 🔧 undo: ⚠️ 删除任务类接口未处理已安排任务块的解除逻辑 - 当前删除任务类时,未解除已被安排的任务块 - 该逻辑存在缺陷,计划在后续版本内修复 🛠️
This commit is contained in:
@@ -47,18 +47,18 @@ func (d *CacheDAO) AddTaskClassList(ctx context.Context, userID int, list *model
|
||||
return d.client.Set(ctx, key, data, 30*time.Minute).Err()
|
||||
}
|
||||
|
||||
func (d *CacheDAO) GetTaskClassList(ctx context.Context, userID int) (model.UserGetTaskClassesResponse, error) {
|
||||
func (d *CacheDAO) GetTaskClassList(ctx context.Context, userID int) (*model.UserGetTaskClassesResponse, error) {
|
||||
key := fmt.Sprintf("smartflow:task_classes:%d", userID)
|
||||
var resp model.UserGetTaskClassesResponse
|
||||
// 1. 从 Redis 获取字符串
|
||||
val, err := d.client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
// 注意:如果是 redis.Nil,交给 Service 层处理查库逻辑
|
||||
return resp, err
|
||||
return &resp, err
|
||||
}
|
||||
// 2. 反序列化:将 JSON 还原回结构体
|
||||
err = json.Unmarshal([]byte(val), &resp)
|
||||
return resp, err
|
||||
return &resp, err
|
||||
}
|
||||
|
||||
func (d *CacheDAO) DeleteTaskClassList(ctx context.Context, userID int) error {
|
||||
@@ -136,3 +136,73 @@ func (d *CacheDAO) DeleteUserTodayScheduleFromCache(ctx context.Context, userID
|
||||
key := fmt.Sprintf("smartflow:today_schedule:%d", userID)
|
||||
return d.client.Del(ctx, key).Err()
|
||||
}
|
||||
|
||||
func (d *CacheDAO) GetUserWeeklyScheduleFromCache(ctx context.Context, userID int, week int) (*model.UserWeekSchedule, error) {
|
||||
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, week)
|
||||
var schedules model.UserWeekSchedule
|
||||
val, err := d.client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
return nil, err // 注意:如果是 redis.Nil,交给 Service 层处理查库逻辑
|
||||
}
|
||||
err = json.Unmarshal([]byte(val), &schedules)
|
||||
return &schedules, err
|
||||
}
|
||||
|
||||
func (d *CacheDAO) SetUserWeeklyScheduleToCache(ctx context.Context, userID int, schedules *model.UserWeekSchedule) error {
|
||||
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, schedules.Week)
|
||||
data, err := json.Marshal(schedules)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 设置过期时间为一天
|
||||
return d.client.Set(ctx, key, data, 24*time.Hour).Err()
|
||||
}
|
||||
|
||||
func (d *CacheDAO) DeleteUserWeeklyScheduleFromCache(ctx context.Context, userID int, week int) error {
|
||||
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, week)
|
||||
return d.client.Del(ctx, key).Err()
|
||||
}
|
||||
|
||||
func (d *CacheDAO) GetUserRecentCompletedSchedulesFromCache(ctx context.Context, userID, index, limit int) (model.UserRecentCompletedScheduleResponse, error) {
|
||||
key := fmt.Sprintf("smartflow:recent_completed_schedules:%d:%d:%d", userID, index, limit)
|
||||
var resp model.UserRecentCompletedScheduleResponse
|
||||
val, err := d.client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
return resp, err // 注意:如果是 redis.Nil,交给 Service 层处理查库逻辑
|
||||
}
|
||||
err = json.Unmarshal([]byte(val), &resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (d *CacheDAO) SetUserRecentCompletedSchedulesToCache(ctx context.Context, userID, index, limit int, resp model.UserRecentCompletedScheduleResponse) error {
|
||||
key := fmt.Sprintf("smartflow:recent_completed_schedules:%d:%d:%d", userID, index, limit)
|
||||
data, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 设置过期时间为30分钟
|
||||
return d.client.Set(ctx, key, data, 30*time.Minute).Err()
|
||||
}
|
||||
|
||||
func (d *CacheDAO) DeleteUserRecentCompletedSchedulesFromCache(ctx context.Context, userID int) error {
|
||||
pattern := fmt.Sprintf("smartflow:recent_completed_schedules:%d:*", userID)
|
||||
|
||||
var cursor uint64
|
||||
for {
|
||||
keys, next, err := d.client.Scan(ctx, cursor, pattern, 500).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(keys) > 0 {
|
||||
// 用 UNLINK\(\) 异步删除,降低阻塞风险;如需强一致删除可改用 Del\(\)
|
||||
if err := d.client.Unlink(ctx, keys...).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cursor = next
|
||||
if cursor == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -463,3 +463,24 @@ func (d *ScheduleDAO) GetUserRecentCompletedSchedules(ctx context.Context, nowTi
|
||||
}
|
||||
return schedules, nil
|
||||
}
|
||||
|
||||
func (d *ScheduleDAO) GetScheduleEventWeekByID(ctx context.Context, eventID int) (int, error) {
|
||||
type row struct {
|
||||
Week *int `gorm:"column:week"`
|
||||
}
|
||||
var r row
|
||||
err := d.db.WithContext(ctx).
|
||||
Table("schedules").
|
||||
Select("week").
|
||||
Where("event_id = ?", eventID).
|
||||
Order("id ASC").
|
||||
Limit(1).
|
||||
Scan(&r).Error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if r.Week == nil {
|
||||
return 0, respond.WrongScheduleEventID
|
||||
}
|
||||
return *r.Week, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user