fix: 隔离日计划策略并发初始化事务
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
package cn.code.nl.module.lms.controller.admin.dailyplan.vo;
|
||||
|
||||
import cn.code.nl.module.system.api.user.AdminUserApi;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import org.dromara.core.trans.anno.Trans;
|
||||
import org.dromara.core.trans.constant.TransType;
|
||||
import org.dromara.core.trans.vo.VO;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -18,7 +15,6 @@ public class DailyPlanStrategyRespVO implements VO {
|
||||
private Integer strategyMode;
|
||||
private Long cursorDailyPlanId;
|
||||
private Integer version;
|
||||
@Trans(type = TransType.AUTO_TRANS, key = AdminUserApi.PREFIX, fields = "nickname", ref = "updaterName")
|
||||
private String updater;
|
||||
private String updaterName;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@@ -309,6 +309,7 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
||||
DailyPlanStrategyDO strategy = strategyInitializer.getOrCreate(type);
|
||||
result.add(convertStrategy(strategy));
|
||||
}
|
||||
resolveStrategyUpdaterNames(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -736,6 +737,14 @@ public class DailyPlanServiceImpl implements DailyPlanService {
|
||||
plans.forEach(plan -> plan.setUpdaterName(resolveOperatorName(plan.getUpdater(), userMap)));
|
||||
}
|
||||
|
||||
/** 批量解析策略修改人,避免转换组件把系统调度标识当作用户 ID。 */
|
||||
private void resolveStrategyUpdaterNames(List<DailyPlanStrategyRespVO> strategies) {
|
||||
Set<Long> userIds = strategies.stream().map(DailyPlanStrategyRespVO::getUpdater)
|
||||
.map(DailyPlanServiceImpl::parseOperatorId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
Map<Long, AdminUserRespDTO> userMap = userIds.isEmpty() ? Map.of() : adminUserApi.getUserMap(userIds);
|
||||
strategies.forEach(strategy -> strategy.setUpdaterName(resolveOperatorName(strategy.getUpdater(), userMap)));
|
||||
}
|
||||
|
||||
/** 将日计划数据对象逐字段转换为响应对象。 */
|
||||
private DailyPlanRespVO convertPlan(DailyPlanDO plan) {
|
||||
DailyPlanRespVO response = new DailyPlanRespVO();
|
||||
|
||||
@@ -8,6 +8,9 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.lms.enums.ErrorCodeConstants.DAILY_PLAN_STRATEGY_NOT_EXISTS;
|
||||
@@ -20,8 +23,26 @@ public class DailyPlanStrategyInitializer {
|
||||
|
||||
@Resource
|
||||
private DailyPlanStrategyMapper strategyMapper;
|
||||
@Resource
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
public DailyPlanStrategyDO getOrCreate(DailyPlanStrategyTypeEnum type) {
|
||||
TransactionTemplate transaction = new TransactionTemplate(transactionManager);
|
||||
transaction.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
try {
|
||||
return transaction.execute(status -> loadOrInsert(type));
|
||||
} catch (DuplicateKeyException ignored) {
|
||||
// 冲突事务已经完整回滚;新事务读取可见的并发提交,规避 MySQL RR 旧快照。
|
||||
DailyPlanStrategyDO concurrent = transaction.execute(
|
||||
status -> strategyMapper.selectByStrategyType(type.getCode()));
|
||||
if (concurrent != null) {
|
||||
return concurrent;
|
||||
}
|
||||
throw exception(DAILY_PLAN_STRATEGY_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private DailyPlanStrategyDO loadOrInsert(DailyPlanStrategyTypeEnum type) {
|
||||
DailyPlanStrategyDO current = strategyMapper.selectByStrategyType(type.getCode());
|
||||
if (current != null) {
|
||||
return current;
|
||||
@@ -37,15 +58,7 @@ public class DailyPlanStrategyInitializer {
|
||||
strategy.setVersion(0);
|
||||
strategy.setCreator(SYSTEM_OPERATOR);
|
||||
strategy.setUpdater(SYSTEM_OPERATOR);
|
||||
try {
|
||||
strategyMapper.insert(strategy);
|
||||
return strategy;
|
||||
} catch (DuplicateKeyException ignored) {
|
||||
DailyPlanStrategyDO concurrent = strategyMapper.selectByStrategyType(type.getCode());
|
||||
if (concurrent != null) {
|
||||
return concurrent;
|
||||
}
|
||||
throw exception(DAILY_PLAN_STRATEGY_NOT_EXISTS);
|
||||
}
|
||||
strategyMapper.insert(strategy);
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user