| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- package dept
- import (
- "context"
- "fmt"
- authHelper "perms-system-server/internal/logic/auth"
- "perms-system-server/internal/response"
- "perms-system-server/internal/svc"
- "perms-system-server/internal/types"
- "github.com/zeromicro/go-zero/core/logx"
- "github.com/zeromicro/go-zero/core/stores/sqlx"
- )
- type DeleteDeptLogic struct {
- logx.Logger
- ctx context.Context
- svcCtx *svc.ServiceContext
- }
- func NewDeleteDeptLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteDeptLogic {
- return &DeleteDeptLogic{
- Logger: logx.WithContext(ctx),
- ctx: ctx,
- svcCtx: svcCtx,
- }
- }
- // DeleteDept 删除部门。在事务内加行锁后检查是否存在子部门或关联用户,均无则删除。仅超管可调用。
- func (l *DeleteDeptLogic) DeleteDept(req *types.DeleteDeptReq) error {
- if err := authHelper.RequireSuperAdmin(l.ctx); err != nil {
- return err
- }
- return l.svcCtx.SysDeptModel.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
- // 锁序协议:先锁本部门行(X 锁),再对子部门 / 关联用户用 FOR SHARE 做"存在性检查"。
- // 存在性检查不修改目标行,用 S 锁即可,不会与 UpdateUser 改 DeptId(持有 sys_user 行的 X 锁)
- // 或 CreateDept 插子部门(持有 sys_dept 新行的 X 锁)构成 AB-BA 冲突:
- // DeleteDept: sys_dept.X(self) → sys_dept.S(children range) → sys_user.S(dept range)
- // CreateDept: sys_dept.X(newRow) ——独立范围
- // UpdateUser: sys_user.X(self) ± sys_dept.S(newDept existence) ——独立方向
- // 相比之前"全链路 FOR UPDATE"减少一种理论 AB-BA 死锁路径(见审计 L-1)。
- var deptId int64
- lockQuery := fmt.Sprintf("SELECT `id` FROM %s WHERE `id` = ? FOR UPDATE", l.svcCtx.SysDeptModel.TableName())
- if err := session.QueryRowCtx(ctx, &deptId, lockQuery, req.Id); err != nil {
- return response.ErrNotFound("部门不存在")
- }
- var childIds []int64
- childQuery := fmt.Sprintf("SELECT `id` FROM %s WHERE `parentId` = ? FOR SHARE", l.svcCtx.SysDeptModel.TableName())
- if err := session.QueryRowsCtx(ctx, &childIds, childQuery, req.Id); err != nil {
- return err
- }
- if len(childIds) > 0 {
- return response.ErrBadRequest("该部门下存在子部门,无法删除")
- }
- var userIds []int64
- userQuery := fmt.Sprintf("SELECT `id` FROM %s WHERE `deptId` = ? FOR SHARE", l.svcCtx.SysUserModel.TableName())
- if err := session.QueryRowsCtx(ctx, &userIds, userQuery, req.Id); err != nil {
- return err
- }
- if len(userIds) > 0 {
- return response.ErrBadRequest("该部门下仍有关联用户,无法删除")
- }
- return l.svcCtx.SysDeptModel.DeleteWithTx(ctx, session, req.Id)
- })
- }
|