diff --git a/backend/internal/repository/api_key_repo.go b/backend/internal/repository/api_key_repo.go index 7bd846e1..269f0661 100644 --- a/backend/internal/repository/api_key_repo.go +++ b/backend/internal/repository/api_key_repo.go @@ -91,32 +91,35 @@ func (r *apiKeyRepository) GetByKey(ctx context.Context, key string) (*service.A } func (r *apiKeyRepository) Update(ctx context.Context, key *service.ApiKey) error { - exists, err := r.activeQuery().Where(apikey.IDEQ(key.ID)).Exist(ctx) - if err != nil { - return err - } - if !exists { - return service.ErrApiKeyNotFound - } - - builder := r.client.ApiKey.UpdateOneID(key.ID). + // 使用原子操作:将软删除检查与更新合并到同一语句,避免竞态条件。 + // 之前的实现先检查 Exist 再 UpdateOneID,若在两步之间发生软删除, + // 则会更新已删除的记录。 + // 这里选择 Update().Where(),确保只有未软删除记录能被更新。 + // 同时显式设置 updated_at,避免二次查询带来的并发可见性问题。 + now := time.Now() + builder := r.client.ApiKey.Update(). + Where(apikey.IDEQ(key.ID), apikey.DeletedAtIsNil()). SetName(key.Name). - SetStatus(key.Status) + SetStatus(key.Status). + SetUpdatedAt(now) if key.GroupID != nil { builder.SetGroupID(*key.GroupID) } else { builder.ClearGroupID() } - updated, err := builder.Save(ctx) - if err == nil { - key.UpdatedAt = updated.UpdatedAt - return nil + affected, err := builder.Save(ctx) + if err != nil { + return err } - if dbent.IsNotFound(err) { + if affected == 0 { + // 更新影响行数为 0,说明记录不存在或已被软删除。 return service.ErrApiKeyNotFound } - return err + + // 使用同一时间戳回填,避免并发删除导致二次查询失败。 + key.UpdatedAt = now + return nil } func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error { diff --git a/backend/internal/repository/group_repo.go b/backend/internal/repository/group_repo.go index 41ee84fe..a6c7e3cc 100644 --- a/backend/internal/repository/group_repo.go +++ b/backend/internal/repository/group_repo.go @@ -289,8 +289,10 @@ func (r *groupRepository) DeleteCascade(ctx context.Context, id int64) ([]int64, } // 2. Clear group_id for api keys bound to this group. + // 仅更新未软删除的记录,避免修改已删除数据,保证审计与历史回溯一致性。 + // 与 ApiKeyRepository 的软删除语义保持一致,减少跨模块行为差异。 if _, err := txClient.ApiKey.Update(). - Where(apikey.GroupIDEQ(id)). + Where(apikey.GroupIDEQ(id), apikey.DeletedAtIsNil()). ClearGroupID(). Save(ctx); err != nil { return nil, err