From 9d52826555f025ac7d12156e1441e9898be5b146 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Mon, 27 Oct 2025 23:21:15 -0700 Subject: [PATCH] =?UTF-8?q?feat(=E7=BC=93=E5=AD=98):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E6=B8=85=E9=99=A4=E7=94=A8=E6=88=B7=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=BC=93=E5=AD=98=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=BC=93=E5=AD=98=E9=94=AE=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 BatchClearRelatedCache 方法用于批量清除用户相关缓存 优化设备相关缓存键的命名格式以提高一致性 简化设备登录逻辑中孤儿认证方法的处理流程 --- internal/logic/auth/deviceLoginLogic.go | 79 +++++++------------ .../user/bindEmailWithVerificationLogic.go | 19 +++-- internal/model/user/model.go | 5 ++ 3 files changed, 45 insertions(+), 58 deletions(-) diff --git a/internal/logic/auth/deviceLoginLogic.go b/internal/logic/auth/deviceLoginLogic.go index 132ccc8..10f0949 100644 --- a/internal/logic/auth/deviceLoginLogic.go +++ b/internal/logic/auth/deviceLoginLogic.go @@ -86,63 +86,40 @@ func (l *DeviceLoginLogic) DeviceLogin(req *types.DeviceLoginRequest) (resp *typ } if authMethod != nil { - // 认证方法存在但设备记录不存在,可能是数据不一致,先检查用户是否存在 + // 认证方法存在但设备记录不存在,可能是数据不一致,获取用户信息并重新创建设备记录 userInfo, err = l.svcCtx.UserModel.FindOne(l.ctx, authMethod.UserId) if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - // 用户不存在,说明是孤立的认证方法记录,需要清理 - l.Errorw("found orphaned auth method record, cleaning up", - logger.Field("auth_method_id", authMethod.Id), - logger.Field("user_id", authMethod.UserId), - logger.Field("identifier", req.Identifier), - ) - - // 删除孤立的认证方法记录 - if deleteErr := l.svcCtx.UserModel.DeleteUserAuthMethods(l.ctx, authMethod.UserId, authMethod.AuthType); deleteErr != nil { - l.Errorw("failed to delete orphaned auth method", - logger.Field("auth_method_id", authMethod.Id), - logger.Field("error", deleteErr.Error()), - ) - } - - // 创建新用户和设备 - userInfo, err = l.registerUserAndDevice(req) - if err != nil { - return nil, err - } - } else { - l.Errorw("query user by auth method failed", - logger.Field("user_id", authMethod.UserId), - logger.Field("identifier", req.Identifier), - logger.Field("error", err.Error()), - ) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user failed: %v", err.Error()) - } - } else { - // 用户存在,重新创建缺失的设备记录 - deviceInfo := &user.Device{ - Ip: req.IP, - UserId: userInfo.Id, - UserAgent: req.UserAgent, - Identifier: req.Identifier, - Enabled: true, - Online: false, - } - if err := l.svcCtx.UserModel.InsertDevice(l.ctx, deviceInfo); err != nil { - l.Errorw("failed to recreate device record", - logger.Field("user_id", userInfo.Id), - logger.Field("identifier", req.Identifier), - logger.Field("error", err.Error()), - ) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "recreate device record failed: %v", err) - } - - l.Infow("found existing auth method without device record, recreated device record", + l.Errorw("query user by auth method failed", + logger.Field("user_id", authMethod.UserId), + logger.Field("identifier", req.Identifier), + logger.Field("error", err.Error()), + ) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user failed: %v", err.Error()) + } + + // 重新创建缺失的设备记录 + deviceInfo := &user.Device{ + Ip: req.IP, + UserId: userInfo.Id, + UserAgent: req.UserAgent, + Identifier: req.Identifier, + Enabled: true, + Online: false, + } + if err := l.svcCtx.UserModel.InsertDevice(l.ctx, deviceInfo); err != nil { + l.Errorw("failed to recreate device record", logger.Field("user_id", userInfo.Id), logger.Field("identifier", req.Identifier), - logger.Field("device_id", deviceInfo.Id), + logger.Field("error", err.Error()), ) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "recreate device record failed: %v", err) } + + l.Infow("found existing auth method without device record, recreated device record", + logger.Field("user_id", userInfo.Id), + logger.Field("identifier", req.Identifier), + logger.Field("device_id", deviceInfo.Id), + ) } else { // 设备和认证方法都不存在,创建新用户和设备 userInfo, err = l.registerUserAndDevice(req) diff --git a/internal/logic/public/user/bindEmailWithVerificationLogic.go b/internal/logic/public/user/bindEmailWithVerificationLogic.go index bed50dd..dfa81de 100644 --- a/internal/logic/public/user/bindEmailWithVerificationLogic.go +++ b/internal/logic/public/user/bindEmailWithVerificationLogic.go @@ -274,10 +274,13 @@ func (l *BindEmailWithVerificationLogic) transferDeviceToEmailUser(deviceUserId, return nil, err } - // 5. 清除邮箱用户缓存(确保获取最新数据) + // 5. 强制清除邮箱用户的所有相关缓存(确保获取最新数据)// 清除邮箱用户缓存 emailUser, _ := l.svcCtx.UserModel.FindOne(l.ctx, emailUserId) if emailUser != nil { - l.svcCtx.UserModel.ClearUserCache(l.ctx, emailUser) + // 清除用户的批量相关缓存(包括设备、认证方法等) + if err := l.svcCtx.UserModel.BatchClearRelatedCache(l.ctx, emailUser); err != nil { + l.Errorw("清理邮箱用户相关缓存失败", logger.Field("error", err.Error()), logger.Field("user_id", emailUser.Id)) + } } // 6. 清除设备相关缓存 @@ -388,11 +391,13 @@ func (l *BindEmailWithVerificationLogic) createEmailUser(email string) (int64, e func (l *BindEmailWithVerificationLogic) clearDeviceRelatedCache(deviceIdentifier string, oldUserId, newUserId int64) { // 清除设备相关的缓存键 deviceCacheKeys := []string{ - fmt.Sprintf("device:%s", deviceIdentifier), - fmt.Sprintf("user_device:%d", oldUserId), - fmt.Sprintf("user_device:%d", newUserId), - fmt.Sprintf("user_auth:%d", oldUserId), - fmt.Sprintf("user_auth:%d", newUserId), + fmt.Sprintf("cache:device:identifier:%s", deviceIdentifier), + fmt.Sprintf("cache:user:devices:%d", oldUserId), + fmt.Sprintf("cache:user:devices:%d", newUserId), + fmt.Sprintf("cache:user:auth_methods:%d", oldUserId), + fmt.Sprintf("cache:user:auth_methods:%d", newUserId), + fmt.Sprintf("cache:user:%d", oldUserId), + fmt.Sprintf("cache:user:%d", newUserId), } for _, key := range deviceCacheKeys { diff --git a/internal/model/user/model.go b/internal/model/user/model.go index dea27cd..bfe8975 100644 --- a/internal/model/user/model.go +++ b/internal/model/user/model.go @@ -105,6 +105,7 @@ type customUserLogicModel interface { ClearSubscribeCache(ctx context.Context, data ...*Subscribe) error ClearUserCache(ctx context.Context, data ...*User) error + BatchClearRelatedCache(ctx context.Context, user *User) error QueryDailyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) QueryMonthlyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) @@ -243,6 +244,10 @@ func (m *customUserModel) FindOneByReferCode(ctx context.Context, referCode stri return &data, err } +func (m *customUserModel) BatchClearRelatedCache(ctx context.Context, user *User) error { + return m.defaultUserModel.BatchClearRelatedCache(ctx, user) +} + func (m *customUserModel) FindOneSubscribeDetailsById(ctx context.Context, id int64) (*SubscribeDetails, error) { var data SubscribeDetails err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error {