perf: 系统级性能优化与并发安全修复
## 并发安全修复 (4处) - scrap.py: 报废执行添加 SELECT FOR UPDATE 悲观锁,消除 TOCTOU 竞态 - stock.py (adjust_stock): 盘点调整添加 for_update=True 行锁 - outbound_service.py: 低库存预警 SMTP 调用移到 commit 之后,避免长事务 - trans_service.py: execute_dispatch 按 (source_table, id) 排序 items,消除死锁风险 ## N+1 查询优化 (2处) - inventory_task.py: _prefetch_inventory_map 单条 UNION ALL+GROUP BY 替代循环内逐条查询(N*4次→2次) - stock.py (export_stocktake): get_borrowed_qty 批量 GROUP BY 替代逐条 TransBorrow 查询(~18000次→1次) ## BOM 列表性能重构 - bom_service.py: get_bom_list 单条 GROUP BY+string_agg+分页,消除 N+1 循环查询 - bom_service.py: 新增 get_bom_summary (轻量 GROUP BY category+COUNT) - bom.py: 新增 /api/v1/bom/summary 路由,/list 支持 category 过滤 ## Odoo 基础信息懒加载 - base_service.py: 新增 get_odoo_summary (GROUP BY category+COUNT) - base.py: 新增 /api/v1/inbound/base/odoo-summary 路由 - buyOdoo.vue: 懒加载分组架构 (fetchOdooSummary + loadGroupItems) - material_base.ts: 新增 getOdooSummary API ## 前端 Bug 修复 - BomManage.vue: 懒加载分组 (fetchBomSummary + loadGroupItems + collapse) - BomManage.vue: 适配新 API 格式 (res.data.items 替代 res.data) - buyOdoo.vue: 移除 "点击展开加载" 文字 - Selection.vue + borrow/apply/index.vue: openBomSelect 适配新 API 格式
This commit is contained in:
@ -261,19 +261,19 @@ class ScrapService:
|
||||
created_records.append(scrap_record)
|
||||
continue
|
||||
|
||||
# 获取库存记录
|
||||
# 获取库存记录 — ★ 修复并发:使用悲观锁防止超卖/负库存
|
||||
stock_record = None
|
||||
if source_table == 'stock_product':
|
||||
stock_record = StockProduct.query.get(stock_id)
|
||||
stock_record = StockProduct.query.with_for_update().get(stock_id)
|
||||
elif source_table == 'stock_semi':
|
||||
stock_record = StockSemi.query.get(stock_id)
|
||||
stock_record = StockSemi.query.with_for_update().get(stock_id)
|
||||
elif source_table == 'stock_buy':
|
||||
stock_record = StockBuy.query.get(stock_id)
|
||||
stock_record = StockBuy.query.with_for_update().get(stock_id)
|
||||
|
||||
if not stock_record:
|
||||
raise ValueError(f'库存记录不存在: ID={stock_id}')
|
||||
|
||||
# 检查可用数量
|
||||
# 检查可用数量(锁已持有,TOCTOU 窗口已消除)
|
||||
avail_qty = float(stock_record.available_quantity) if stock_record.available_quantity else 0
|
||||
if avail_qty < scrap_qty:
|
||||
raise ValueError(f"SKU {stock_record.sku} 可用库存不足,当前可用: {avail_qty}")
|
||||
|
||||
Reference in New Issue
Block a user