Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
refactor(service): 修改banner和guild删除逻辑为软删除 fix(service): 修复删除操作使用软删除而非物理删除 build: 添加SQLite测试仓库实现 docs: 新增奖励管理字段拆分和批量抽奖UI改造文档 ci: 更新CI忽略文件 style: 清理无用资源文件
6.9 KiB
6.9 KiB
背景
- 当前不启用数据库外键约束(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_issues按activity_id(internal/repository/mysql/model/activity_issues.gen.go:18) - 期下配置与承诺:
- 奖励配置
activity_reward_settings按issue_id(internal/repository/mysql/model/activity_reward_settings.gen.go:18) - 随机承诺
issue_random_commitments按issue_id(internal/repository/mysql/model/issue_random_commitments.gen.go:18)
- 奖励配置
- 期下抽奖相关:
- 抽奖日志
activity_draw_logs按issue_id(internal/repository/mysql/model/activity_draw_logs.gen.go:18) - 抽奖效果
activity_draw_effects按draw_log_id/issue_id(internal/repository/mysql/model/activity_draw_effects.gen.go:17,29) - 抽奖凭据
activity_draw_receipts按draw_log_id(internal/repository/mysql/model/activity_draw_receipts.gen.go:17)
- 抽奖日志
- 活动范围效果与道具:
- 用户道具使用记录
user_item_cards按used_activity_id/used_issue_id/used_draw_log_id(internal/repository/mysql/model/user_item_cards.gen.go:24,25,23) - 抽奖效果快照
activity_draw_effects按activity_id/issue_id(internal/repository/mysql/model/activity_draw_effects.gen.go:28,29)
- 用户道具使用记录
- 资产与日志:
- 用户资产
user_inventory按activity_id(internal/repository/mysql/model/user_inventory.gen.go:21) - 公会贡献日志
guild_contribute_logs按activity_id/issues_id(internal/repository/mysql/model/guild_contribute_logs.gen.go:19,20)
- 用户资产
- 系统模板:
- 系统道具卡
system_item_cards按activity_id/issue_id(internal/repository/mysql/model/system_item_cards.gen.go:23,24) - 系统优惠券
system_coupons按activity_id(internal/repository/mysql/model/system_coupons.gen.go:20)
- 系统道具卡
- 最后删除活动主表:
activities(internal/repository/mysql/model/activities.gen.go:15)
删除用户(Users.ID)
- 用户身份与权益:
- 头衔
user_titles按user_id(internal/repository/mysql/model/user_titles.gen.go:16) - 领取型权益限流
user_title_effect_claims按user_id(internal/repository/mysql/model/user_title_effect_claims.gen.go:16)
- 头衔
- 用户账户与地址:
- 地址
user_addresses按user_id(internal/repository/mysql/model/user_addresses.gen.go:18) - 积分余额
user_points按user_id(internal/repository/mysql/model/user_points.gen.go:18) - 积分流水
user_points_ledger按user_id(internal/repository/mysql/model/user_points_ledger.gen.go:17)
- 地址
- 用户订单与优惠:
- 订单
orders按user_id(internal/repository/mysql/model/orders.gen.go:18) - 用户优惠券
user_coupons按user_id(internal/repository/mysql/model/user_coupons.gen.go:18)
- 订单
- 用户资产与道具:
- 用户资产
user_inventory按user_id(internal/repository/mysql/model/user_inventory.gen.go:18) - 用户道具卡
user_item_cards按user_id(internal/repository/mysql/model/user_item_cards.gen.go:18)
- 用户资产
- 与抽奖相关:
- 抽奖效果
activity_draw_effects按user_id或关联draw_log_id(internal/repository/mysql/model/activity_draw_effects.gen.go:18,17) - 抽奖凭据
activity_draw_receipts关联draw_log_id(internal/repository/mysql/model/activity_draw_receipts.gen.go:17) - 抽奖日志
activity_draw_logs按user_id(internal/repository/mysql/model/activity_draw_logs.gen.go:17)
- 抽奖效果
- 公会关联:
- 公会成员
guild_members按user_id(internal/repository/mysql/model/guild_members.gen.go:18) - 公会贡献日志
guild_contribute_logs按user_id(internal/repository/mysql/model/guild_contribute_logs.gen.go:18)
- 公会成员
- 履约/发货:
- 发货记录
shipping_records按user_id(internal/repository/mysql/model/shipping_records.gen.go:18) - 运营发货统计
ops_shipping_stats按user_id(internal/repository/mysql/model/ops_shipping_stats.gen.go:21)
- 发货记录
- 最后软删用户:
users.deleted_at(internal/repository/mysql/model/users.gen.go:20)
删除顺序(事务内)
- 统一采用“从叶到根”的顺序:
- 以日志/效果/凭据等子表为先(
activity_draw_effects、activity_draw_receipts、activity_draw_logs) - 再清理资产/权益/模板(
user_inventory、user_item_cards、user_titles、system_*) - 清理期与期下配置(
activity_issues、activity_reward_settings、issue_random_commitments) - 删除根实体(
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
后续动作
- 我将基于以上清单与顺序,补充两套事务级联删除实现,并为关键入口替换调用;同时补充单元测试覆盖正常/边界/异常三类用例,验证幂等与性能。