From fce35e8a2d1966b255b281857f5b0afbf1473ea9 Mon Sep 17 00:00:00 2001 From: huang Date: Thu, 9 Apr 2026 11:58:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E5=88=86=E9=85=8D=E6=9D=83=E9=99=90=E5=B9=B6=E5=8F=91=E7=AB=9E?= =?UTF-8?q?=E6=80=81=E5=AF=BC=E8=87=B4=E5=94=AF=E4=B8=80=E7=BA=A6=E6=9D=9F?= =?UTF-8?q?=E5=86=B2=E7=AA=81=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Store 层 Create 方法对唯一约束冲突幂等处理,消除并发写入报错 - Service 层预批量加载角色已有权限集合(1次查询),替换逐条 Exists 查询(N次查询),同时降低竞态窗口 💘 Generated with Crush Assisted-by: Claude Sonnet 4.6 via Crush --- internal/service/role/service.go | 13 +++++++++++-- internal/store/postgres/role_permission_store.go | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/service/role/service.go b/internal/service/role/service.go index 1481ae8..867aa03 100644 --- a/internal/service/role/service.go +++ b/internal/service/role/service.go @@ -223,10 +223,19 @@ func (s *Service) AssignPermissions(ctx context.Context, roleID uint, permIDs [] return nil, errors.New(errors.CodeInvalidParam, fmt.Sprintf("权限 %v 不适用于此角色类型", invalidPermIDs)) } + // 批量获取已有权限集合,避免逐条 Exists 查询 + existingPermIDs, err := s.rolePermissionStore.GetPermIDsByRoleID(ctx, roleID) + if err != nil { + return nil, errors.Wrap(errors.CodeInternalError, err, "获取已有权限失败") + } + existingSet := make(map[uint]bool, len(existingPermIDs)) + for _, id := range existingPermIDs { + existingSet[id] = true + } + var rps []*model.RolePermission for _, permID := range permIDs { - exists, _ := s.rolePermissionStore.Exists(ctx, roleID, permID) - if exists { + if existingSet[permID] { continue } diff --git a/internal/store/postgres/role_permission_store.go b/internal/store/postgres/role_permission_store.go index 20e6eaf..8ae83be 100644 --- a/internal/store/postgres/role_permission_store.go +++ b/internal/store/postgres/role_permission_store.go @@ -23,9 +23,13 @@ func NewRolePermissionStore(db *gorm.DB, redisClient *redis.Client) *RolePermiss } } -// Create 创建角色-权限关联 +// Create 创建角色-权限关联,唯一约束冲突时幂等处理 func (s *RolePermissionStore) Create(ctx context.Context, rp *model.RolePermission) error { if err := s.db.WithContext(ctx).Create(rp).Error; err != nil { + // 并发竞态导致唯一约束冲突,视为已存在,幂等返回 + if isUniqueViolation(err) { + return nil + } return err } s.clearRoleUsersCaches(ctx, rp.RoleID)