package manager import ( "context" "errors" "fmt" "time" "gorm.io/gorm" ) // 公共的事件管理器 // // 作用 // 1. 对外提供统一的缓存操作接口,比如根据ID获取、更新、删除等 // 2. 缓存读取不到的时候会自动从DB加载数据,简化业务代码的实现 // 3. 处理缓存穿透、缓存雪崩等问题,提升系统的稳定性和性能 type EventManager[T any] struct { tx *gorm.DB options *managerOptions ttl time.Duration manager *CacheManager[T] idGetter func(*T) int64 } func NewEventManager[T any](tx *gorm.DB, ttl time.Duration, manager *CacheManager[T], idGetter func(*T) int64, ops ...OptionFunc) *EventManager[T] { options := defaultManagerOptions() for _, op := range ops { op(options) } return &EventManager[T]{ tx: tx, options: options, ttl: ttl, manager: manager, idGetter: idGetter, } } func (l *EventManager[T]) DeleteById(ctx context.Context, id int64) error { err := l.manager.Del(ctx, fmt.Sprintf("%d", id)) if err != nil { l.options.logger.Errorf(ctx, "EventManager DeleteById error: %v", err) return err } l.options.logger.Infof(ctx, "EventManager DeleteById id:%d success", id) return nil } func (l *EventManager[T]) DeleteByKey(ctx context.Context, key string) error { err := l.manager.Del(ctx, key) if err != nil { l.options.logger.Errorf(ctx, "EventManager DeleteByKey error: %v", err) return err } l.options.logger.Infof(ctx, "EventManager DeleteByKey key:%s success", key) return nil } func (e *EventManager[T]) UpdateById(ctx context.Context, id int64) error { _, err := e.UpdateByIdWithValue(ctx, id) return err } func (e *EventManager[T]) UpdateByIdWithValue(ctx context.Context, id int64) (*T, error) { // 查询DB & 更新缓存 data := new(T) err := e.tx.WithContext(ctx).Where("id = ?", id).First(data).Error if err != nil { e.options.logger.Errorf(ctx, "EventManager UpdateByIdWithValue id:%d db query error: %v", id, err) return nil, err } err = e.manager.Set(ctx, fmt.Sprintf("%d", id), data, e.ttl, []int64{id}) if err != nil { e.options.logger.Errorf(ctx, "EventManager cache set id:%d error: %v", id, err) return nil, err } e.options.logger.Infof(ctx, "EventManager cache update id:%d", id) return data, nil } func (e *EventManager[T]) GetById(ctx context.Context, id int64) (*T, error) { key := fmt.Sprintf("%d", id) data, err := e.manager.Get(ctx, key) if err != nil && !errors.Is(err, ErrCacheNil) { e.options.logger.Errorf(ctx, "EventManager Get id:%d error: %v", id, err) return nil, err } if data != nil { e.options.logger.Infof(ctx, "EventManager get by cache id:%d", id) return data, nil } // TODO: 缓存雪崩问题,这里需要处理一下,比如设置一个兜底数据之类的 d, err := e.UpdateByIdWithValue(ctx, id) if err != nil { e.options.logger.Errorf(ctx, "EventManager UpdateByIdWithValue id:%d err:%v", id, err) return nil, err } return d, nil } func (e *EventManager[T]) GetByIds(ctx context.Context, ids []int64) ([]*T, error) { resp := make([]*T, 0, len(ids)) keys := make([]string, 0, len(ids)) keyMap := make(map[string]struct{}, len(ids)) for _, id := range ids { key := fmt.Sprintf("%d", id) keys = append(keys, key) keyMap[key] = struct{}{} } // global.Logger.Infof(ctx, "get by cache ids:%v keys:%+v", ids, keys) respMap, err := e.manager.BatchGet(ctx, keys) if err != nil { e.options.logger.Errorf(ctx, "EventManager cache batch get ids:%v error: %v", ids, err) return nil, err } // e.options.logger.Infof(ctx, "get by cache ids:%v,respMap:%+v", ids, respMap) dbs := make([]string, 0) for key := range keyMap { if val, ok := respMap[key]; ok { resp = append(resp, val) } else { dbs = append(dbs, key) } } if len(dbs) > 0 { dbQuerys := make([]*T, 0, len(dbs)) db := e.tx.WithContext(ctx).Where("id in (?)", dbs) err := db.Find(&dbQuerys).Error if err != nil { e.options.logger.Errorf(ctx, "EventManager db query ids:%v error: %v", dbs, err) return nil, err } for _, v := range dbQuerys { resp = append(resp, v) err = e.manager.Set(ctx, fmt.Sprintf("%d", e.idGetter(v)), v, e.ttl, []int64{e.idGetter(v)}) if err != nil { e.options.logger.Errorf(ctx, "EventManager cache set id:%d error: %v", e.idGetter(v), err) } } } return resp, nil } func (l *EventManager[T]) GetByFields(ctx context.Context, fields map[string]interface{}) ([]*T, error) { resp, err := l.manager.GetByFields(ctx, fields, l.ttl) if err == nil { return resp, nil } return l.manager.UpdateByFields(ctx, fields, l.ttl) } func (e *EventManager[T]) DeleteCacheById(ctx context.Context, id int64) error { key := fmt.Sprintf("%d", id) return e.manager.Del(ctx, key) } func (e *EventManager[T]) DeleteCacheByIds(ctx context.Context, ids []int64) error { keys := make([]string, 0, len(ids)) for _, id := range ids { keys = append(keys, fmt.Sprintf("%d", id)) } return e.manager.BatchDel(ctx, keys) } func (e *EventManager[T]) DeleteCacheByFields(ctx context.Context, fields map[string]interface{}) error { key := e.manager.fieldsToKey(fields) return e.manager.Del(ctx, fmt.Sprintf("%v", key)) } func (e *EventManager[T]) BatchDel(ctx context.Context, keys []string) error { return e.manager.BatchDel(ctx, keys) }