bindbox-game/.trae/documents/删除级联逻辑优化方案.md
邹方成 2a89a1ab9d
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
feat(admin): 更新前端资源文件及修复相关功能
refactor(service): 修改banner和guild删除逻辑为软删除
fix(service): 修复删除操作使用软删除而非物理删除

build: 添加SQLite测试仓库实现
docs: 新增奖励管理字段拆分和批量抽奖UI改造文档

ci: 更新CI忽略文件
style: 清理无用资源文件
2025-11-19 01:35:55 +08:00

6.9 KiB
Raw Blame History

背景

  • 当前不启用数据库外键约束FK删除由业务逻辑驱动。
  • 现有删除实现多为单表删除,未做级联:如删除活动 internal/service/activity/activity_delete.go:9、删除期 internal/service/activity/issue_delete.go:9、删除用户 internal/service/user/batch_user.go:32
  • GORM 初始化未声明外键或级联:internal/repository/mysql/mysql.go:97

目标

  • 在业务层实现“逻辑级联删除”,保证删除主实体时,同步清理其关联业务数据,且性能与可控性优于 FK 级联。

级联清单

删除活动Activities.ID

  • 删除活动期:activity_issuesactivity_idinternal/repository/mysql/model/activity_issues.gen.go:18
  • 期下配置与承诺:
    • 奖励配置 activity_reward_settingsissue_idinternal/repository/mysql/model/activity_reward_settings.gen.go:18
    • 随机承诺 issue_random_commitmentsissue_idinternal/repository/mysql/model/issue_random_commitments.gen.go:18
  • 期下抽奖相关:
    • 抽奖日志 activity_draw_logsissue_idinternal/repository/mysql/model/activity_draw_logs.gen.go:18
    • 抽奖效果 activity_draw_effectsdraw_log_id/issue_idinternal/repository/mysql/model/activity_draw_effects.gen.go:17,29
    • 抽奖凭据 activity_draw_receiptsdraw_log_idinternal/repository/mysql/model/activity_draw_receipts.gen.go:17
  • 活动范围效果与道具:
    • 用户道具使用记录 user_item_cardsused_activity_id / used_issue_id / used_draw_log_idinternal/repository/mysql/model/user_item_cards.gen.go:24,25,23
    • 抽奖效果快照 activity_draw_effectsactivity_id/issue_idinternal/repository/mysql/model/activity_draw_effects.gen.go:28,29
  • 资产与日志:
    • 用户资产 user_inventoryactivity_idinternal/repository/mysql/model/user_inventory.gen.go:21
    • 公会贡献日志 guild_contribute_logsactivity_id / issues_idinternal/repository/mysql/model/guild_contribute_logs.gen.go:19,20
  • 系统模板:
    • 系统道具卡 system_item_cardsactivity_id / issue_idinternal/repository/mysql/model/system_item_cards.gen.go:23,24
    • 系统优惠券 system_couponsactivity_idinternal/repository/mysql/model/system_coupons.gen.go:20
  • 最后删除活动主表:activitiesinternal/repository/mysql/model/activities.gen.go:15

删除用户Users.ID

  • 用户身份与权益:
    • 头衔 user_titlesuser_idinternal/repository/mysql/model/user_titles.gen.go:16
    • 领取型权益限流 user_title_effect_claimsuser_idinternal/repository/mysql/model/user_title_effect_claims.gen.go:16
  • 用户账户与地址:
    • 地址 user_addressesuser_idinternal/repository/mysql/model/user_addresses.gen.go:18
    • 积分余额 user_pointsuser_idinternal/repository/mysql/model/user_points.gen.go:18
    • 积分流水 user_points_ledgeruser_idinternal/repository/mysql/model/user_points_ledger.gen.go:17
  • 用户订单与优惠:
    • 订单 ordersuser_idinternal/repository/mysql/model/orders.gen.go:18
    • 用户优惠券 user_couponsuser_idinternal/repository/mysql/model/user_coupons.gen.go:18
  • 用户资产与道具:
    • 用户资产 user_inventoryuser_idinternal/repository/mysql/model/user_inventory.gen.go:18
    • 用户道具卡 user_item_cardsuser_idinternal/repository/mysql/model/user_item_cards.gen.go:18
  • 与抽奖相关:
    • 抽奖效果 activity_draw_effectsuser_id 或关联 draw_log_idinternal/repository/mysql/model/activity_draw_effects.gen.go:18,17
    • 抽奖凭据 activity_draw_receipts 关联 draw_log_idinternal/repository/mysql/model/activity_draw_receipts.gen.go:17
    • 抽奖日志 activity_draw_logsuser_idinternal/repository/mysql/model/activity_draw_logs.gen.go:17
  • 公会关联:
    • 公会成员 guild_membersuser_idinternal/repository/mysql/model/guild_members.gen.go:18
    • 公会贡献日志 guild_contribute_logsuser_idinternal/repository/mysql/model/guild_contribute_logs.gen.go:18
  • 履约/发货:
    • 发货记录 shipping_recordsuser_idinternal/repository/mysql/model/shipping_records.gen.go:18
    • 运营发货统计 ops_shipping_statsuser_idinternal/repository/mysql/model/ops_shipping_stats.gen.go:21
  • 最后软删用户:users.deleted_atinternal/repository/mysql/model/users.gen.go:20

删除顺序(事务内)

  • 统一采用“从叶到根”的顺序:
    1. 以日志/效果/凭据等子表为先(activity_draw_effectsactivity_draw_receiptsactivity_draw_logs
    2. 再清理资产/权益/模板(user_inventoryuser_item_cardsuser_titlessystem_*
    3. 清理期与期下配置(activity_issuesactivity_reward_settingsissue_random_commitments
    4. 删除根实体(activities 或软删 users
  • 全过程包裹在单事务中,任何一步失败则回滚。

实现策略

  • 新增业务服务方法:
    • DeleteActivityCascade(ctx, activityID):按“删除活动”清单顺序删除
    • DeleteUserCascade(ctx, userID):按“删除用户”清单顺序删除
  • 技术要点:
    • 批量删除使用分批(如 5k/批)避免长事务与大锁;必要时按时间/ID 片段迭代
    • 统一 WHERE 条件与索引列(user_id/activity_id/issue_id/draw_log_id)确保扫描性能
    • 软删与硬删:保留用户软删(合规与审计),其余按当前表定义硬删;如需统一软删,可后续逐表补充 gorm.DeletedAt
    • 幂等性:每个子删除操作按条件删除,无记录时直接通过;重复调用不报错
    • 审计记录操作日志操作者、对象ID、影响行数便于回溯

验收标准

  • 删除活动时,任一期及其抽奖日志/效果/凭据、奖励配置、承诺、资产、贡献日志与相关模板均被清理;根活动删除成功。
  • 删除用户时,地址/订单/优惠券/积分(余额+流水)/资产/道具/抽奖相关/公会关系/发货记录及统计均被清理;根用户软删成功。
  • 全流程事务保障、失败回滚;批量删除性能稳定,无显著锁表或超时。

需要改造的现有入口(参考)

  • 活动删除入口:internal/service/activity/activity_delete.go:9 → 升级为调用 DeleteActivityCascade
  • 期删除入口:internal/service/activity/issue_delete.go:9 → 被 DeleteActivityCascade 内部调用(或保留独立级联)
  • 用户删除入口:internal/service/user/batch_user.go:32 → 升级为调用 DeleteUserCascade

后续动作

  • 我将基于以上清单与顺序,补充两套事务级联删除实现,并为关键入口替换调用;同时补充单元测试覆盖正常/边界/异常三类用例,验证幂等与性能。