05 管理活动与选品

运营端位于 seckill-admin, 功能围绕活动的配置与管理展开, 入口分三类: 登录、主域视图 (选品数据源)、活动管理与选品。

登录 (UserController)

入口为 POST /user/login, 仅一个登录方法: 调用 support 提供的 UserDubboService 完成凭证校验与 JWT 签发。网关侧虽有统一的鉴权/授权体系,但登录接口本身在白名单中 (未登录也要能访问), 所以 admin 侧要再做一次角色校验------只允许管理员账号登录管理后台:

java 复制代码
@PostMapping ("/login")
public Result<LoginResponse> login (@Valid @RequestBody LoginRequest request) {
    LoginResponse response = userService.login (request);
    Integer roleCode = response.getUser () == null ? null : response.getUser (). getRole ();
    if (Role.fromCode (roleCode) != Role. ADMIN) {
        throw new BizException (ResultEnum.FORBIDDEN.getCode (), "仅管理员可登录管理后台");
    }
    return Result.success (response);
}

主域视图 (SupportProductController)

主域只以 Dubbo 对外暴露能力, 浏览器无法直接访问, 因此需要为选品在 admin 中提供一个主域商品与 SKU 的只读转发入口。它持有 support 的 ProductDubboService 与 SkuDubboService, 提供四个查询:

端点 用途
GET /support/product/list 主域商品分页(选品列表页)
GET /support/product/{spuNo} 单个主域商品
GET /support/product/{spuNo}/skus 商品(SPU)下全部 SKU(勾选数据源)
GET /support/product/sku/{skuNo} 单个主域 SKU

活动管理与配置 (ActivityController)

其余功能全部收在 ActivityController 中 (活动管理、配置、选品统一入口)。要点: 在 seckill-base 里活动与 SKU 是严格分开的两个子域, admin 侧需要聚合两者来处理。

生命周期: 管理端只提供暂停、继续、关闭 (激活由定时任务自动完成)------直接复用 base 活动侧接口;

创建、更新、删除: 只与秒杀域活动有关, 同样直接复用 base 接口;

查询:列表 (全量/按状态) 与单个查询直接复用 base; 另多一个"详情", 由 admin 聚合"活动 + 该活动下的 SKU 列表"返回 (ActivityDetailVO), 供详情页一次拉取。

活动选品 : 跨域编排

选品流程: 前端先经 SupportProductController 展示主域商品与 SKU, 运营勾选并设置秒杀价、划拨库存等, 再提交给 ActivityController 完成添加。除库存外的字段都是静态配置,唯独库存必须保证"总量守恒" (主域库存与秒杀域配额此消彼长), 因此这一步是跨域写操作, 由 admin 做两段事务编排。

添加 (主域划拨 → 秒杀域落库)

java 复制代码
// 阶段一:批量划拨 (support 域内单事务: 整批扣 / 零扣)
try {
    skuService.batchDeductStock (stockItems);           // 原子扣减 + 按 skuNo 排序防死锁
} catch (Exception e) {
    BizException biz = findBizException (e);
    if (biz != null) throw biz;                        // 确认失败: 已回滚, 零副作用, 直接上抛
    // 未知结果: 不动作、转人工
    throw new BizException (SYSTEM_ERROR, "库存划拨结果未知,请人工核对主域库存后再决定是否重试");
}

// 阶段二:秒杀域批量落库 (base 域内单事务: 整批插 / 零插)
try {
    seckillProductSkuService.batchAdd (request);
} catch (Exception e) {
    BizException biz = findBizException (e);
    if (biz != null) {
        restoreStock (activityNo, stockItems, "添加失败补偿归还");   // 确认失败 → 整批补偿归还
        throw biz;
    }
    // 未知结果: 查证已落库则按成功返回, 否则转人工
    if (! verifyAdded (activityNo, stockItems)) {
        throw new BizException (SYSTEM_ERROR, "落库结果未知,请人工核对活动商品后再决定是否重试");
    }
}

主域扣减的两道防护: CAS 语义的原子扣减 (WHERE stock >= quantity, 数量不足则影响 0 行)+ 批量按 skuNo 排序执行 (多活动同时划拨同一批 SKU 时, 统一加锁顺序、不会死锁)。

删除 (秒杀域删除 → 主域归还)

秒杀域删除是整体删行, 删完之后行就消失、配额不可再查------所以归还数量必须先预读快照, 它是"超时后恢复归还"的唯一依据:

java 复制代码
List<StockChangeItem> preReadItems = preReadQuota (activityNo, skuNos);   // 预读配额快照
try {
    restoreItems = seckillProductSkuService.batchRemove (request)...;     // 阶段一: 秒杀域批量删
} catch (Exception e) {
    if (确认失败) throw biz;                                             // 零删除, 无需归还
    restoreItems = verifyRemoved (activityNo, skuNos, preReadItems);      // 未知: 查证是否已删
    if (restoreItems == null) { /* 未删/读取失败 → 转人工 */ }
}
restoreStock (activityNo, restoreItems, "删除归还");                      // 阶段二: 主域归还

失败裁决原则

结果形态 判定方式 处理
确认失败 异常链含 BizException(事务已回滚=零副作用) 补偿归还可安全重试(≤3 次);或直接上抛
未知结果(超时等) 无 BizException 不重试写操作;能查证的先查证(base 侧有查询接口),查无结论转人工
查证手段 只做读(verifyAdded / verifyRemoved) 秒杀域可查证;主域库存无查询能力 → 归还超时只能转人工

涉及库存的写操作,未知状态下绝不重试写 (防止双重效果); 重试只用于"确认失败后的补偿"与"读查证"------宁可留给人工核对, 不可重复动库存。

添加与删除跨两域执行, 但没有任何"横跨两域的锁": 每个域各自"单事务 + 失败补偿", 跨域层面不存在持锁等待; 域内层面的等待 (活动行闸门、排序后的行锁) 只排队、不成环。

相关推荐
Rain的Java大神之路32 分钟前
国家数据集团校招、社招都开了:总部雄安,这些技术岗值得认真看看
java·后端·面试
吴名氏.40 分钟前
Java转AI Agent教程(第九周)错误矩阵
java·人工智能·矩阵·ai agent
文丑颜不良啊43 分钟前
LeetCode1901~1920题目解析
java·leetcode
tealcwu1 小时前
【Unity基础】为什么游戏需要物理按键映射?从 Unity Input Manager 到跨引擎输入设计
java·游戏·unity
vipxieliang1 小时前
Spring Boot 性能优化实战:从启动加速到运行时调优
java·spring boot
AI全栈学习助手1 小时前
告别“转圈等待”:Spring Boot + SSE 让大模型像 ChatGPT 一样流式输出
java·人工智能·spring boot·后端·aigc
天天被压力1 小时前
【A股分钟级高频数据完全手册 #02】Python调用股票1分钟数据接口:Pro版最新分时取数与字段解析
java·人工智能·python
代码不停1 小时前
Spring Aop
java·数据库·spring
道尔柯南2 小时前
C++ STL 入门详解:从认识标准模板库到掌握学习方法
java·c++·学习方法