fix: 批量任务详情查询不再写库,修复 ConcurrencyStamp 冲突
- MapJobOutputAsync 改为只读聚合,GET /jobs/{id} 不再 UpdateJob
- /jobs/{id}/items 仅校验存在,避免并行查询双写
- 重写 migrate_rename_warehouse_C_to_c.sql,支持 Navicat 与大小写两步改名
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a1daea6b35
commit
c2d854b83f
@ -1,34 +1,123 @@
|
||||
-- 仓储表 C_* → c_*(小写前缀,对齐 t_* 命名风格)
|
||||
-- 可重复执行:源表不存在或目标表已存在则跳过
|
||||
-- 仓储表 C_* → c_*(小写 c 前缀)
|
||||
-- 不依赖 DELIMITER / 存储过程,Navicat、DMS、mysql 命令行均可整段执行
|
||||
-- 可重复执行
|
||||
--
|
||||
-- 说明:
|
||||
-- 1) 若库已开启 lower_case_table_names(Windows/部分云库),建表时 C_sku 磁盘上已是 c_sku,
|
||||
-- 无需 RENAME,部署新代码即可;下方「诊断」应只看到 c_*。
|
||||
-- 2) Linux 且区分大小写时,须经临时表名两步改名,否则可能报 Table 'c_sku' already exists。
|
||||
-- 3) 执行前请确认已 USE 到业务库(DATABASE() 不能为 NULL)。
|
||||
|
||||
DROP PROCEDURE IF EXISTS sp_rename_warehouse_table_if_needed;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE sp_rename_warehouse_table_if_needed(IN old_name VARCHAR(128), IN new_name VARCHAR(128))
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = old_name
|
||||
) AND NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = new_name
|
||||
) THEN
|
||||
SET @ddl := CONCAT('RENAME TABLE `', old_name, '` TO `', new_name, '`');
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
-- ========== 诊断(先看当前表名)==========
|
||||
SELECT TABLE_NAME AS warehouse_table
|
||||
FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND (
|
||||
TABLE_NAME LIKE 'C\_%' ESCAPE '\\'
|
||||
OR TABLE_NAME LIKE 'c\_%' ESCAPE '\\'
|
||||
OR TABLE_NAME LIKE '\_\_oms\_ren\_%' ESCAPE '\\'
|
||||
)
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
CALL sp_rename_warehouse_table_if_needed('C_sku', 'c_sku');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_bin_location', 'c_bin_location');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_inventory', 'c_inventory');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_inbound_notice', 'c_inbound_notice');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_inbound_box', 'c_inbound_box');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_inbound_box_line', 'c_inbound_box_line');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_parcel', 'c_parcel');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_parcel_arrival', 'c_parcel_arrival');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_parcel_item', 'c_parcel_item');
|
||||
CALL sp_rename_warehouse_table_if_needed('C_sku_platform_map', 'c_sku_platform_map');
|
||||
-- ========== 单表改名:大写 C_ 存在 → 临时名 → c_* ==========
|
||||
-- c_sku
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_sku');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_sku` TO `__oms_ren_sku`', 'SELECT ''skip: C_sku'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_sku');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_sku` TO `c_sku`', 'SELECT ''skip: __oms_ren_sku'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
DROP PROCEDURE IF EXISTS sp_rename_warehouse_table_if_needed;
|
||||
-- c_bin_location
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_bin_location');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_bin_location` TO `__oms_ren_bin_location`', 'SELECT ''skip: C_bin_location'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_bin_location');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_bin_location` TO `c_bin_location`', 'SELECT ''skip: __oms_ren_bin_location'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_inventory
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inventory');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_inventory` TO `__oms_ren_inventory`', 'SELECT ''skip: C_inventory'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inventory');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inventory` TO `c_inventory`', 'SELECT ''skip: __oms_ren_inventory'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_inbound_notice
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_notice');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_notice` TO `__oms_ren_inbound_notice`', 'SELECT ''skip: C_inbound_notice'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_notice');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_notice` TO `c_inbound_notice`', 'SELECT ''skip: __oms_ren_inbound_notice'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_inbound_box
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_box');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_box` TO `__oms_ren_inbound_box`', 'SELECT ''skip: C_inbound_box'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_box');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_box` TO `c_inbound_box`', 'SELECT ''skip: __oms_ren_inbound_box'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_inbound_box_line
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_box_line');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_box_line` TO `__oms_ren_inbound_box_line`', 'SELECT ''skip: C_inbound_box_line'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_box_line');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_box_line` TO `c_inbound_box_line`', 'SELECT ''skip: __oms_ren_inbound_box_line'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_parcel
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel` TO `__oms_ren_parcel`', 'SELECT ''skip: C_parcel'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel` TO `c_parcel`', 'SELECT ''skip: __oms_ren_parcel'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_parcel_arrival
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel_arrival');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel_arrival` TO `__oms_ren_parcel_arrival`', 'SELECT ''skip: C_parcel_arrival'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel_arrival');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel_arrival` TO `c_parcel_arrival`', 'SELECT ''skip: __oms_ren_parcel_arrival'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_parcel_item
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel_item');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel_item` TO `__oms_ren_parcel_item`', 'SELECT ''skip: C_parcel_item'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel_item');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel_item` TO `c_parcel_item`', 'SELECT ''skip: __oms_ren_parcel_item'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- c_sku_platform_map
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_sku_platform_map');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `C_sku_platform_map` TO `__oms_ren_sku_platform_map`', 'SELECT ''skip: C_sku_platform_map'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_sku_platform_map');
|
||||
SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_sku_platform_map` TO `c_sku_platform_map`', 'SELECT ''skip: __oms_ren_sku_platform_map'' AS info');
|
||||
PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
|
||||
|
||||
-- ========== 执行后复查 ==========
|
||||
SELECT TABLE_NAME AS warehouse_table_after
|
||||
FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME LIKE 'c\_%' ESCAPE '\\'
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
-- ========== 若上面全是 skip 且已是 c_*:无需再改,直接部署后端即可 ==========
|
||||
-- 若仍残留 C_*(区分大小写 Linux),可手工一次性执行(会失败则勿重复跑):
|
||||
-- RENAME TABLE
|
||||
-- `C_sku` TO `__oms_ren_sku`, `C_bin_location` TO `__oms_ren_bin_location`,
|
||||
-- `C_inventory` TO `__oms_ren_inventory`, `C_inbound_notice` TO `__oms_ren_inbound_notice`,
|
||||
-- `C_inbound_box` TO `__oms_ren_inbound_box`, `C_inbound_box_line` TO `__oms_ren_inbound_box_line`,
|
||||
-- `C_parcel` TO `__oms_ren_parcel`, `C_parcel_arrival` TO `__oms_ren_parcel_arrival`,
|
||||
-- `C_parcel_item` TO `__oms_ren_parcel_item`, `C_sku_platform_map` TO `__oms_ren_sku_platform_map`;
|
||||
-- RENAME TABLE
|
||||
-- `__oms_ren_sku` TO `c_sku`, `__oms_ren_bin_location` TO `c_bin_location`,
|
||||
-- `__oms_ren_inventory` TO `c_inventory`, `__oms_ren_inbound_notice` TO `c_inbound_notice`,
|
||||
-- `__oms_ren_inbound_box` TO `c_inbound_box`, `__oms_ren_inbound_box_line` TO `c_inbound_box_line`,
|
||||
-- `__oms_ren_parcel` TO `c_parcel`, `__oms_ren_parcel_arrival` TO `c_parcel_arrival`,
|
||||
-- `__oms_ren_parcel_item` TO `c_parcel_item`, `__oms_ren_sku_platform_map` TO `c_sku_platform_map`;
|
||||
|
||||
@ -400,6 +400,9 @@ public sealed class OrderBatchJobCoordinator(
|
||||
return await MapJobOutputAsync(job, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<OrderBatchJob?> GetJobEntityAsync(int jobId, CancellationToken cancellationToken = default) =>
|
||||
batchJobRepository.GetByIdAsync(jobId, cancellationToken);
|
||||
|
||||
public async Task<List<OrderBatchJobItemOutput>> GetJobItemsAsync(int jobId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var job = await batchJobRepository.GetByIdAsync(jobId, cancellationToken);
|
||||
@ -541,39 +544,39 @@ public sealed class OrderBatchJobCoordinator(
|
||||
var runningCount = items.Count(x => x.Status == OrderBatchJobItemStatusCodes.Running);
|
||||
var cancelledCount = items.Count(x => x.Status == OrderBatchJobItemStatusCodes.Cancelled);
|
||||
|
||||
if (job.SuccessCount != successCount || job.FailCount != failCount)
|
||||
{
|
||||
job.SuccessCount = successCount;
|
||||
job.FailCount = failCount;
|
||||
}
|
||||
|
||||
// 只读聚合:查询接口不得写库,避免与 MQ 消费者并发更新 ConcurrencyStamp 冲突。
|
||||
var status = job.Status;
|
||||
var finishedAt = job.FinishedAt;
|
||||
if (items.Count > 0 && items.All(x =>
|
||||
x.Status is OrderBatchJobItemStatusCodes.Success
|
||||
or OrderBatchJobItemStatusCodes.Failed
|
||||
or OrderBatchJobItemStatusCodes.Cancelled))
|
||||
{
|
||||
job.Status = cancelledCount == items.Count
|
||||
status = cancelledCount == items.Count
|
||||
? OrderBatchJobStatusCodes.Cancelled
|
||||
: failCount > 0 && successCount == 0
|
||||
? OrderBatchJobStatusCodes.Failed
|
||||
: OrderBatchJobStatusCodes.Completed;
|
||||
job.FinishedAt ??= DateTime.Now;
|
||||
await batchJobRepository.UpdateJobAsync(job, cancellationToken);
|
||||
finishedAt ??= items
|
||||
.Where(x => x.FinishedAt.HasValue)
|
||||
.Select(x => x.FinishedAt)
|
||||
.OrderByDescending(x => x)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
var output = new OrderBatchJobOutput
|
||||
{
|
||||
JobId = job.Id,
|
||||
Action = job.Action,
|
||||
Status = job.Status,
|
||||
Status = status,
|
||||
Total = job.Total,
|
||||
SuccessCount = job.SuccessCount,
|
||||
FailCount = job.FailCount,
|
||||
SuccessCount = successCount,
|
||||
FailCount = failCount,
|
||||
PendingCount = pendingCount,
|
||||
RunningCount = runningCount,
|
||||
CancelledCount = cancelledCount,
|
||||
StartedAt = job.StartedAt,
|
||||
FinishedAt = job.FinishedAt,
|
||||
FinishedAt = finishedAt,
|
||||
CreateTime = job.CreateTime,
|
||||
};
|
||||
ApplyImportMetadata(output, job);
|
||||
|
||||
@ -59,7 +59,7 @@ public partial class OrderService
|
||||
[HttpGet("/order/batch/jobs/{id:int}/items")]
|
||||
public async Task<List<OrderBatchJobItemOutput>> GetBatchJobItemsAsync([FromRoute] int id)
|
||||
{
|
||||
var job = await BatchJobCoordinator.GetJobAsync(id);
|
||||
var job = await BatchJobCoordinator.GetJobEntityAsync(id);
|
||||
if (job == null)
|
||||
{
|
||||
throw new BusinessException("批量任务不存在");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user