根据 Shop No 批量变更合作伙伴并记录变更日志(my Sql 实战)
根据 Shop No 批量变更合作伙伴并记录变更日志(my Sql 实战)
背景
在实际业务中,经常会遇到这样的需求:
- 一个合作伙伴(Partner)可能关联多个店铺(Shop)
- 由于业务调整,需要根据 shopNo 批量变更店铺所属的合作伙伴
- 同时要求完整记录变更历史,用于审计、回溯或问题排查
本文通过一个完整的 MySQL 实战示例,演示如何:
- 根据
shopNo批量更新supplier_PartnerShopRls中的PartnerId - 同步写入变更记录表
supplier_partnershoprlchangerecords - 使用变量 + 事务,保证可复用性与数据安全
一、相关表说明
1️⃣ 合作伙伴表(supplier_Partners)
IdPartnerNo
2️⃣ 店铺表(product_shops)
IdshopNo
3️⃣ 合作伙伴与店铺关系表(supplier_PartnerShopRls)
ShopIdPartnerId
4️⃣ 变更记录表(supplier_partnershoprlchangerecords)
用于记录 Partner 变更历史,核心字段包括:
Id:手动生成(当前最大值 + 1)ShopIdOldPartnerIdNewPartnerIdConcurrencyStamp:MD5(UUID())CreationTime
二、变量化设计(可重复执行)
实际操作中,最容易变化的只有两个条件:
- 目标合作伙伴编号
- 需要处理的 shopNo 列表
因此我们通过变量统一管理:
1
2
3
SET @TargetPartnerNo = 'P20240001';
SET @ShopNos = 'S001,S002,S003';
SET @CreateUserId = 0;
后续脚本无需改动主体逻辑,只需替换变量即可。
三、核心思路
整个操作分为两个步骤,且必须放在同一个事务中:
- 先插入变更记录(记录旧值 → 新值)
- 再更新关系表数据
并额外注意:
- 只记录“确实发生变化”的数据
- 防止重复执行导致脏数据
四、获取变更记录 Id 起始值
由于 Id 不是自增,需要手动生成:
1
2
3
4
SELECT @StartId := IFNULL(MAX(Id), 0)
FROM dev_supplier.supplier_partnershoprlchangerecords;
SET @RowNum := 0;
后续通过 @StartId + 行号 的方式生成连续 Id。
五、插入变更记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
INSERT INTO dev_supplier.supplier_partnershoprlchangerecords
(
Id,
ShopId,
OldPartnerId,
NewPartnerId,
ExtraProperties,
ConcurrencyStamp,
CreationTime,
CreateUserId,
LastModificationTime,
DeletionTime,
IsDeleted
)
SELECT
@StartId + (@RowNum := @RowNum + 1) AS Id,
rl.ShopId,
rl.PartnerId AS OldPartnerId,
newp.Id AS NewPartnerId,
'{}',
MD5(UUID()),
NOW(),
@CreateUserId,
NULL,
NULL,
0
FROM supplier_PartnerShopRls rl
JOIN dev_product.product_shops shop
ON rl.ShopId = shop.Id
JOIN supplier_Partners newp
ON newp.PartnerNo = @TargetPartnerNo
WHERE FIND_IN_SET(shop.shopNo, @ShopNos) > 0
AND rl.PartnerId <> newp.Id;
关键点:
rl.PartnerId <> newp.Id:避免无变化也写日志MD5(UUID()):符合 ABP 常见并发标识风格
六、更新主表关系
1
2
3
4
5
6
7
8
UPDATE supplier_PartnerShopRls rl
JOIN dev_product.product_shops shop
ON rl.ShopId = shop.Id
JOIN supplier_Partners newp
ON newp.PartnerNo = @TargetPartnerNo
SET rl.PartnerId = newp.Id
WHERE FIND_IN_SET(shop.shopNo, @ShopNos) > 0
AND rl.PartnerId <> newp.Id;
七、完整事务版本(生产推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
START TRANSACTION;
SET @TargetPartnerNo = 'P20240001';
SET @ShopNos = 'S001,S002,S003';
SET @CreateUserId = 0;
SELECT @StartId := IFNULL(MAX(Id), 0)
FROM dev_supplier.supplier_partnershoprlchangerecords;
SET @RowNum := 0;
-- 插入变更记录
INSERT INTO dev_supplier.supplier_partnershoprlchangerecords
(
Id, ShopId, OldPartnerId, NewPartnerId,
ExtraProperties, ConcurrencyStamp, CreationTime,
CreateUserId, LastModificationTime, DeletionTime, IsDeleted
)
SELECT
@StartId + (@RowNum := @RowNum + 1),
rl.ShopId,
rl.PartnerId,
newp.Id,
'{}',
MD5(UUID()),
NOW(),
@CreateUserId,
NULL,
NULL,
0
FROM supplier_PartnerShopRls rl
JOIN dev_product.product_shops shop ON rl.ShopId = shop.Id
JOIN supplier_Partners newp ON newp.PartnerNo = @TargetPartnerNo
WHERE FIND_IN_SET(shop.shopNo, @ShopNos) > 0
AND rl.PartnerId <> newp.Id;
-- 更新主表
UPDATE supplier_PartnerShopRls rl
JOIN dev_product.product_shops shop ON rl.ShopId = shop.Id
JOIN supplier_Partners newp ON newp.PartnerNo = @TargetPartnerNo
SET rl.PartnerId = newp.Id
WHERE FIND_IN_SET(shop.shopNo, @ShopNos) > 0
AND rl.PartnerId <> newp.Id;
COMMIT;
如有问题,可直接 ROLLBACK。
八、方案优点总结
- ✅ 变量化设计,复用成本极低
- ✅ 日志与数据强一致(事务)
- ✅ 避免无效更新与重复记录
- ✅ Id 规则与现有系统完全兼容
- ✅ 非侵入式,适合直接用于生产
如果你在项目中也遇到类似的“批量变更 + 审计日志”需求,这套模式可以直接复用。
本文由作者按照 CC BY 4.0 进行授权