This commit is contained in:
2026-06-22 10:00:54 +08:00
parent 0141365c61
commit 5477ae58f4
2 changed files with 26 additions and 4 deletions
@@ -498,7 +498,7 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl<TourUserAssig
if (!TourUserAssignment.PERSON_TYPE_FORMAL.equals(personType)) {
throw new IllegalArgumentException("只有正式人员可以选择分配路线");
}
NutMap matterInfo = fetchMatterInfo(assignment.getSettingId(), matterId);
NutMap matterInfo = fetchMatterInfoForUpdate(assignment.getSettingId(), matterId);
if (matterInfo == null) {
throw new IllegalArgumentException("分配路线不存在或未配置线路");
}
@@ -524,6 +524,13 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl<TourUserAssig
}
String normalizedPersonType = normalizePersonType(personType);
NutMap matterInfo = prepareMatterInfoForAssignment(settingId, matterId, normalizedPersonType);
// 分工会代报名占用事项最大成团人数;在同一事务中锁定事项行,避免多个分工会同时校验通过后并发写入导致超额。
if (matterInfo != null) {
matterInfo = fetchMatterInfoForUpdate(settingId, matterInfo.getString("matterId"));
if (matterInfo == null) {
throw new IllegalArgumentException("疗休养事项不存在或未配置线路");
}
}
TourSetting setting = fetchSettingForAssignment(settingId);
if (setting == null) {
throw new IllegalArgumentException("疗休养配置不存在");
@@ -1252,6 +1259,21 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl<TourUserAssig
}
private NutMap fetchMatterInfo(String settingId, String matterId) {
return fetchMatterInfo(settingId, matterId, false);
}
/**
* 在分工会代报名容量校验前锁定事项行,保证同一事项的“统计人数-校验上限-写入台账”串行执行。
* 该方法必须在 controller 已开启的事务中调用,FOR UPDATE 锁会持续到事务提交或回滚。
*/
private NutMap fetchMatterInfoForUpdate(String settingId, String matterId) {
return fetchMatterInfo(settingId, matterId, true);
}
/**
* 查询事项和线路快照信息;forUpdate 为 true 时追加行锁,用于并发容量控制。
*/
private NutMap fetchMatterInfo(String settingId, String matterId, boolean forUpdate) {
Sql sql = Sqls.create("""
SELECT
m.id AS matterId,
@@ -1271,7 +1293,7 @@ public class TourUserAssignmentServiceImpl extends BaseServiceImpl<TourUserAssig
LEFT JOIN tour_line l ON l.id = m.lineId
LEFT JOIN tour_travel_agency ta ON ta.id = l.travelAgencyId
$condition
""");
""" + (forUpdate ? " FOR UPDATE" : ""));
Cnd cnd = Cnd.NEW();
cnd.and("m.delFlag", "=", false);
cnd.and("m.enabled", "=", true);