fix:重复分配问题修复

This commit is contained in:
2025-12-08 15:05:40 +08:00
parent 1def68600d
commit a0204eff8f
9 changed files with 318 additions and 153 deletions

View File

@@ -245,20 +245,20 @@ public class FabController {
if (REGION_CODE.get("内部加工").equals(materInfo.getPoint_code())) {
List<SendVehicleVo> mater = materInfo.getMater();
if (CollUtil.isEmpty(mater)) throw new BadRequestException("物料信息为空,请确认!");
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.NBJG.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue());
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.NBJG.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue(),false);
if (ObjectUtil.isEmpty(schBasePoint)) {
throw new BadRequestException("仓库收货区域点位已满请清理");
}
toJSON.put("material_info", mater);
toJSON.put("region_code", RegionEnum.NBJG.getRegion_code());
} else if (REGION_CODE.get("外协加工").equals(materInfo.getPoint_code())) {
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.WXJG.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue());
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.WXJG.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue(),false);
if (ObjectUtil.isEmpty(schBasePoint)) {
throw new BadRequestException("外协加工区域点位已满请清理");
}
toJSON.put("region_code", RegionEnum.WXJG.getRegion_code());
} else if (REGION_CODE.get("内部过道").equals(materInfo.getPoint_code())) {
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.NBGD.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue());
SchBasePoint schBasePoint = iSchBasePointService.selectGroundByRegionCode(RegionEnum.NBGD.getRegion_code(), GoodsEnum.OUT_OF_STOCK.getValue(),false);
if (ObjectUtil.isEmpty(schBasePoint)) {
throw new BadRequestException("内部过道区域点位已满请清理");
}

View File

@@ -120,6 +120,7 @@ public interface ISchBasePointService extends IService<SchBasePoint> {
*/
SchBasePoint selectByReassign(String region_code, String vehicleCode);
/**
* 根据区域及托盘类型获取库存信息
*
@@ -191,7 +192,7 @@ public interface ISchBasePointService extends IService<SchBasePoint> {
* @param targetRegionCode
* @param value
*/
SchBasePoint selectGroundByRegionCode(String targetRegionCode, String value);
SchBasePoint selectGroundByRegionCode(String targetRegionCode, String value, Boolean isLock);
/**
* 选择登录设备

View File

@@ -2,6 +2,7 @@ package org.nl.wms.sch.point.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
@@ -49,11 +50,10 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* @author lyd
* @description 服务实现
@@ -164,8 +164,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
pointMapper.insert(entity);
}
// 修复1修改方法添加synchronized
@Override
public void update(SchBasePoint entity) {
public synchronized void update(SchBasePoint entity) {
String currentUserId = SecurityUtils.getCurrentUserId();
String nickName = SecurityUtils.getCurrentNickName();
String now = DateUtil.now();
@@ -196,8 +197,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
pointMapper.deleteBatchIds(ids);
}
// 修复2修改方法添加synchronized
@Override
public void changeUsed(JSONObject jsonObject) {
public synchronized void changeUsed(JSONObject jsonObject) {
// 不可能为空
JSONArray data = jsonObject.getJSONArray("data");
Boolean used = jsonObject.getBoolean("used");
@@ -226,8 +228,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
return this.getOne(lam);
}
// 修复3修改方法添加synchronized
@Override
public void updateStatus(JSONObject jsonObject) {
public synchronized void updateStatus(JSONObject jsonObject) {
String device_code = jsonObject.getString("device_code");
Integer state = jsonObject.getInteger("state");
@@ -258,7 +261,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
@Override
@Transactional(rollbackFor = Exception.class)
public SchBasePoint selectByRegionCode(String region_code, String vehicleCode, String piont_type) {
synchronized (lock2) {
synchronized (SchBasePointServiceImpl.class) {
//查询载具的类型
MdBaseVehicle mdBaseVehicle = iMdBaseVehicleService.selectByVehicleCode(vehicleCode);
if (ObjectUtil.isEmpty(mdBaseVehicle)) throw new BadRequestException("载具类型不存在!");
@@ -279,14 +282,17 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
* @return
*/
private SchBasePoint getSchBasePoint(String regionCode, String pointType, MdBaseVehicle mdBaseVehicle) {
synchronized (SchBasePointServiceImpl.class) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getPoint_type, pointType)
.eq(StrUtil.isNotEmpty(regionCode),SchBasePoint::getRegion_code, regionCode)
.eq(StrUtil.isNotEmpty(regionCode), SchBasePoint::getRegion_code, regionCode)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.eq(SchBasePoint::getCan_vehicle_type, mdBaseVehicle.getVehicle_type())
.eq(SchBasePoint::getIs_used, true));
.eq(SchBasePoint::getIs_used, true)
// 修复4添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
@@ -295,6 +301,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
return schBasePoint;
}
return null;
}
}
@Override
@@ -306,6 +313,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
@Override
public SchBasePoint selectByReassign(String region_code, String vehicleCode) {
synchronized (SchBasePointServiceImpl.class) {
//查询载具的类型
MdBaseVehicle mdBaseVehicle = iMdBaseVehicleService.getById(vehicleCode);
if (ObjectUtil.isEmpty(mdBaseVehicle)) throw new BadRequestException("载具类型不存在!");
@@ -316,7 +324,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
.eq(SchBasePoint::getRegion_code, region_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.eq(SchBasePoint::getCan_vehicle_type, mdBaseVehicle.getVehicle_type())
.eq(SchBasePoint::getIs_used, true));
.eq(SchBasePoint::getIs_used, true)
// 修复5添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint1 = schBasePoints.get(0);
SchBasePoint schBasePoint = pointMapper.selectById(schBasePoint1.getNext_wait_point());
@@ -334,7 +344,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
.isNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getCan_vehicle_type, mdBaseVehicle.getVehicle_type())
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue()));
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
// 修复6添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints1) && schBasePoints1.size() > 0) {
SchBasePoint schBasePoint1 = schBasePoints1.get(0);
SchBasePoint schBasePoint = pointMapper.selectById(schBasePoint1.getNext_wait_point());
@@ -348,14 +360,18 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
return null;
}
}
@Override
public SchBasePoint selectByNextWaitPoint(String device_code, String vehicleCode) {
synchronized (SchBasePointServiceImpl.class) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getNext_wait_point, device_code)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getIs_lock, false).isNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue()));
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
// 修复7添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setVehicle_code(vehicleCode);
@@ -367,15 +383,20 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
return null;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public SchBasePoint selectByVehicleQty(String vehicle_type) {
synchronized (SchBasePointServiceImpl.class) {
Assert.noNullElements(new Object[]{vehicle_type}, "载具类型不能为空!");
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNotNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.EMPTY_PALLETS.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type));
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
// 修复8添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollectionUtils.isEmpty(schBasePoints)) {
return null;
}
@@ -385,115 +406,172 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
.eq("point_code", schBasePoint.getPoint_code()));
return schBasePoint;
}
}
@Override
public SchBasePoint selectByEmptyVehicleType(String vehicle_type) {
synchronized (SchBasePointServiceImpl.class) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
.isNull(SchBasePoint::getVehicle_code));
.isNull(SchBasePoint::getVehicle_code)
// 修复9添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
return (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) ? schBasePoints.get(0) : null;
}
}
// 修复10调整事务与锁顺序 - 外层锁,内部事务方法
@Override
public SchBasePoint selectByGroundPoint(String region_code, String pointStatus, String vehicle_type, int seq, int point_type) {
synchronized (SchBasePointServiceImpl.class) {
return transactionalSelectByGroundPoint(region_code, pointStatus, vehicle_type, seq, point_type);
}
}
// 抽取事务逻辑到私有方法
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public SchBasePoint transactionalSelectByGroundPoint(String region_code, String pointStatus, String vehicle_type, int seq, int point_type) {
// 2. 构建查询条件(抽取公共方法)
LambdaQueryWrapper<SchBasePoint> wrapper = buildQueryWrapper(region_code, pointStatus, vehicle_type, seq, point_type, true);
wrapper.last("LIMIT 1 FOR UPDATE"); // 加行锁+限制1条
SchBasePoint schBasePoint = pointMapper.selectOne(wrapper);
// 3. 降级查询
if (schBasePoint == null) {
log.warn("带region_code[{}]查询点位为空降级查询忽略region_code", region_code);
wrapper = buildQueryWrapper(region_code, pointStatus, vehicle_type, seq, point_type, false);
wrapper.last("LIMIT 1 FOR UPDATE");
schBasePoint = pointMapper.selectOne(wrapper);
}
// 4. 锁定点位
if (schBasePoint != null) {
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
int updateCount = pointMapper.updateById(schBasePoint);
if (updateCount == 0) {
log.error("点位[{}]锁定失败,可能已被其他线程修改", schBasePoint.getPoint_code());
throw new RuntimeException("点位锁定失败");
}
log.info("成功锁定点位:{}region_code{}", schBasePoint.getPoint_code(), schBasePoint.getRegion_code());
return schBasePoint;
}
log.warn("未查询到可用点位参数region_code={}, vehicle_type={}, seq={}", region_code, vehicle_type, seq);
return null;
}
// 抽取公共查询条件
private LambdaQueryWrapper<SchBasePoint> buildQueryWrapper(String regionCode, String pointStatus, String vehicleType, int seq, int pointType, boolean includeRegionCode) {
LambdaQueryWrapper<SchBasePoint> wrapper = Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus);
// 明确拆分条件,提升可读性
if (!"G01".equals(vehicleType)) {
wrapper.eq(SchBasePoint::getPoint_type, "1");
} else {
wrapper.eq(SchBasePoint::getPoint_type, pointType);
}
if (StrUtil.isNotBlank(vehicleType)) {
wrapper.eq(SchBasePoint::getCan_vehicle_type, vehicleType);
}
if (seq == 2) {
wrapper.isNull(SchBasePoint::getVehicles)
.orderByAsc(SchBasePoint::getIn_order_seq);
} else if (seq == 1) {
wrapper.isNull(SchBasePoint::getVehicle_code);
}
if (includeRegionCode && StrUtil.isNotBlank(regionCode)) {
wrapper.eq(SchBasePoint::getRegion_code, regionCode);
}
return wrapper;
}
// 修复11调整事务与锁顺序 - 外层锁,内部事务方法
@Override
public SchBasePoint selectByEmptyCage(String region_code, String vehicle_type, String pointStatus, boolean isVehicle, SchBaseTask task) {
synchronized (SchBasePointServiceImpl.class) {
return transactionalSelectByEmptyCage(region_code, vehicle_type, pointStatus, isVehicle, task);
}
}
// 抽取事务逻辑到私有方法
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public SchBasePoint transactionalSelectByEmptyCage(String region_code, String vehicle_type, String pointStatus, boolean isVehicle, SchBaseTask task) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus)
.eq(!vehicle_type.equals("G01"), SchBasePoint::getPoint_type, "1")
.eq(vehicle_type.equals("G01"), SchBasePoint::getPoint_type, point_type)
.eq(StrUtil.isNotBlank(vehicle_type), SchBasePoint::getCan_vehicle_type, vehicle_type)
.isNull(seq == 2, SchBasePoint::getVehicles)
.isNull(seq == 1, SchBasePoint::getVehicle_code)
.eq(StrUtil.isNotBlank(region_code), SchBasePoint::getRegion_code, region_code)
.orderByAsc(seq == 2, SchBasePoint::getIn_order_seq));
if (CollUtil.isEmpty(schBasePoints)) {
schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus)
.eq(!vehicle_type.equals("G01"), SchBasePoint::getPoint_type, "1")
.eq(vehicle_type.equals("G01"), SchBasePoint::getPoint_type, point_type)
.eq(StrUtil.isNotBlank(vehicle_type), SchBasePoint::getCan_vehicle_type, vehicle_type)
.isNull(seq == 2, SchBasePoint::getVehicles)
.isNull(seq == 1, SchBasePoint::getVehicle_code)
.orderByAsc(seq == 2, SchBasePoint::getIn_order_seq));
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
.isNotNull(SchBasePoint::getVehicle_code)
.orderByDesc(SchBasePoint::getIn_order_seq)
// 修复12添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
updateById(schBasePoint);
return schBasePoint;
}
return (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) ? schBasePoints.get(0) : null;
schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus)
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
.eq(SchBasePoint::getRegion_code, region_code)
.isNotNull(SchBasePoint::getVehicles)
.orderByDesc(SchBasePoint::getIn_order_seq)
// 修复13添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
List<String> msg = new ArrayList<>();
String vehicles = schBasePoint.getVehicles();
boolean contains = vehicles.contains(",");
if (contains) {
String[] split = vehicles.split(",");
msg = Arrays.asList(split);
} else {
msg.add(vehicles);
}
Integer vehicle_qty = schBasePoint.getVehicle_qty();
if (vehicle_qty != msg.size()) throw new BadRequestException("载具数量与载具编码数量不一致!");
String s = msg.get(msg.size() - 1);
schBasePoint.setVehicle_qty(vehicle_qty - 1);
msg.remove(s);
schBasePoint.setVehicles(JSONUtil.toJsonStr(msg));
this.updateById(schBasePoint);
if (schBasePoint.getVehicle_qty() == 0) {
update(Wrappers.lambdaUpdate(SchBasePoint.class)
.eq(SchBasePoint::getPoint_code, schBasePoint.getPoint_code())
.set(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.set(SchBasePoint::getVehicles, null));
}
SchBasePoint schBasePoint1 = null;
if (vehicle_qty == 1) {
schBasePoint1 = selectByPointCode(schBasePoint.getPoint_code());
} else {
schBasePoint1 = selectByPointCode(schBasePoint.getPoint_code() + "_" + (vehicle_qty - 1));
}
if (ObjectUtil.isEmpty(schBasePoint1)) throw new BadRequestException("该货位不存在!");
schBasePoint1.setVehicle_code(s);
schBasePoint1.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint1);
updateById(schBasePoint1);
return schBasePoint1;
}
return null;
}
// 修复14修改方法添加synchronized
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public SchBasePoint selectByEmptyCage(String region_code, String vehicle_type, String pointStatus, boolean isVehicle, SchBaseTask task) {
synchronized (lock) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus)
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
.isNotNull(SchBasePoint::getVehicle_code)
.orderByDesc(SchBasePoint::getIn_order_seq));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
updateById(schBasePoint);
return schBasePoint;
}
schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, pointStatus)
.eq(SchBasePoint::getCan_vehicle_type, vehicle_type)
.eq(SchBasePoint::getRegion_code, region_code)
.isNotNull(SchBasePoint::getVehicles)
.orderByDesc(SchBasePoint::getIn_order_seq));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
List<String> msg = new ArrayList<>();
String vehicles = schBasePoint.getVehicles();
boolean contains = vehicles.contains(",");
if (contains) {
String[] split = vehicles.split(",");
msg = Arrays.asList(split);
} else {
msg.add(vehicles);
}
Integer vehicle_qty = schBasePoint.getVehicle_qty();
if (vehicle_qty != msg.size()) throw new BadRequestException("载具数量与载具编码数量不一致!");
String s = msg.get(msg.size() - 1);
schBasePoint.setVehicle_qty(vehicle_qty - 1);
msg.remove(s);
schBasePoint.setVehicles(JSONUtil.toJsonStr(msg));
this.updateById(schBasePoint);
if (schBasePoint.getVehicle_qty() == 0) {
update(Wrappers.lambdaUpdate(SchBasePoint.class)
.eq(SchBasePoint::getPoint_code, schBasePoint.getPoint_code())
.set(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.set(SchBasePoint::getVehicles, null));
}
SchBasePoint schBasePoint1 = null;
if (vehicle_qty == 1) {
schBasePoint1 = selectByPointCode(schBasePoint.getPoint_code());
} else {
schBasePoint1 = selectByPointCode(schBasePoint.getPoint_code() + "_" + (vehicle_qty - 1));
}
if (ObjectUtil.isEmpty(schBasePoint1)) throw new BadRequestException("该货位不存在!");
schBasePoint1.setVehicle_code(s);
schBasePoint1.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint1);
updateById(schBasePoint1);
return schBasePoint1;
}
return null;
}
}
@Override
public void updatePointLock(String region_code, Boolean lock) {
public synchronized void updatePointLock(String region_code, Boolean lock) {
update(Wrappers.lambdaUpdate(SchBasePoint.class)
.eq(SchBasePoint::getRegion_code, region_code)
.set(SchBasePoint::getIs_lock, lock));
@@ -505,15 +583,55 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
@Override
public SchBasePoint selectGroundByRegionCode(String targetRegionCode, String value) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public SchBasePoint selectGroundByRegionCode(String targetRegionCode, String pointStatus, Boolean isLock) {
// ========== 1. 参数合法性校验(提前拦截无效请求) ==========
Assert.notNull(pointStatus, "点位状态pointStatus不能为空");
Assert.notNull(isLock, "是否锁定标识isLock不能为空");
log.info("[按区域查地面点位] 开始查询,目标区域编码:{},点位状态:{},是否锁定:{}",
targetRegionCode, pointStatus, isLock);
// ========== 2. 构建查询条件(优化可读性,加行锁+LIMIT 1 ==========
LambdaQueryWrapper<SchBasePoint> queryWrapper = Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
.eq(SchBasePoint::getPoint_status, value)
.eq(SchBasePoint::getPoint_status, pointStatus)
.isNull(SchBasePoint::getVehicle_code)
.eq(StrUtil.isNotBlank(targetRegionCode), SchBasePoint::getRegion_code, targetRegionCode)
.orderByAsc(SchBasePoint::getIn_order_seq));
return (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) ? schBasePoints.get(0) : null;
.orderByAsc(SchBasePoint::getIn_order_seq);
// 优化动态条件拆分if-else提升可读性替代原eq(StrUtil.isNotBlank(...))
if (StrUtil.isNotBlank(targetRegionCode)) {
queryWrapper.eq(SchBasePoint::getRegion_code, targetRegionCode);
}
// 核心优化LIMIT 1 避免全量查询 + FOR UPDATE 加行锁(保障并发安全)
queryWrapper.last("LIMIT 1 FOR UPDATE");
// ========== 3. 执行查询仅查1条性能最优 ==========
SchBasePoint targetPoint = pointMapper.selectOne(queryWrapper);
if (targetPoint == null) {
log.warn("[按区域查地面点位] 未查询到可用点位,目标区域编码:{},点位状态:{}", targetRegionCode, pointStatus);
return null;
}
// ========== 4. 按需锁定点位(校验更新结果,避免假锁定) ==========
if (Boolean.TRUE.equals(isLock)) {
targetPoint.setIs_lock(true);
PointUtils.setUpdateByAcs(targetPoint);
int updateCount = pointMapper.updateById(targetPoint);
// 校验更新结果:更新失败则抛异常触发事务回滚
if (updateCount == 0) {
log.error("[按区域查地面点位] 点位锁定失败,点位编码:{}", targetPoint.getPoint_code());
throw new RuntimeException("点位锁定失败,点位编码:" + targetPoint.getPoint_code());
}
log.info("[按区域查地面点位] 点位锁定成功,点位编码:{},区域编码:{}",
targetPoint.getPoint_code(), targetPoint.getRegion_code());
} else {
log.info("[按区域查地面点位] 无需锁定,返回点位:{}", targetPoint.getPoint_code());
}
return targetPoint;
}
@Override
@@ -588,7 +706,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
@Override
public SchBasePoint selectPointByEmpAndRegion(String region_code, String vehicle_code, String s) {
synchronized (lock4) {
synchronized (SchBasePointServiceImpl.class) {
//查询载具的类型
MdBaseVehicle mdBaseVehicle = iMdBaseVehicleService.getById(vehicle_code);
if (ObjectUtil.isEmpty(mdBaseVehicle)) throw new BadRequestException("载具类型不存在!");
@@ -599,7 +717,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
.eq(SchBasePoint::getPoint_type, s)
.eq(SchBasePoint::getRegion_code, region_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.OUT_OF_STOCK.getValue())
.eq(SchBasePoint::getIs_used, true));
.eq(SchBasePoint::getIs_used, true)
// 修复15添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) {
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
@@ -612,7 +732,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
@Override
@Transactional
public SchBasePoint selectStackPoint(String regionCode, String pointStatus, String vehicleType, int seq, int point_type) {
synchronized (SchBasePointServiceImpl.class) {
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.eq(SchBasePoint::getIs_used, true)
@@ -622,7 +744,9 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
.eq(SchBasePoint::getRegion_code, regionCode)
.isNull(seq == 2, SchBasePoint::getVehicles)
.isNull(seq == 1, SchBasePoint::getVehicle_code)
.orderByAsc( SchBasePoint::getIn_order_seq));
.orderByAsc(SchBasePoint::getIn_order_seq)
// 修复16添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
SchBasePoint schBasePoint = (CollUtil.isNotEmpty(schBasePoints) && schBasePoints.size() > 0) ? schBasePoints.get(0) : null;
if (ObjectUtil.isNotEmpty(schBasePoint)) {
schBasePoint.setIs_lock(true);
@@ -631,6 +755,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
return schBasePoint;
}
}
@Override
public List<OrderMater> getStructList(String pointCode, String vehicle_type) {
@@ -657,7 +782,7 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
}
}
else{
structList = pointMapper.getStructList(schBasePoint.getRegion_code(),s);
structList = pointMapper.getStructList(schBasePoint.getRegion_code(),s);
}
List<OrderMater> collect = structList.stream().collect(Collectors.groupingBy(
OrderMater::getVehicle_code,
@@ -679,34 +804,44 @@ public class SchBasePointServiceImpl extends ServiceImpl<SchBasePointMapper, Sch
return timestamp;
}
// 修复17调整事务与锁顺序 - 外层锁,内部事务方法
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public SchBasePoint selectEmpVehicleByRegionCode(String region_code, String vehicleType) {
synchronized (lock3) {
//查询满足条件的站点
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNotNull(SchBasePoint::getVehicle_code)
.eq(StrUtil.isNotEmpty(region_code), SchBasePoint::getRegion_code, region_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.EMPTY_PALLETS.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicleType)
.eq(SchBasePoint::getIs_used, true));
if (CollectionUtils.isEmpty(schBasePoints)) {
schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNotNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.EMPTY_PALLETS.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicleType)
.eq(SchBasePoint::getIs_used, true));
}
if (schBasePoints.size() == 0) {
return null;
}
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointMapper.updateById(schBasePoint);
return schBasePoint;
synchronized (SchBasePointServiceImpl.class) {
return transactionalSelectEmpVehicleByRegionCode(region_code, vehicleType);
}
}
// 抽取事务逻辑到私有方法
@Transactional(propagation = Propagation.REQUIRES_NEW)
public SchBasePoint transactionalSelectEmpVehicleByRegionCode(String region_code, String vehicleType) {
//查询满足条件的站点
List<SchBasePoint> schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNotNull(SchBasePoint::getVehicle_code)
.eq(StrUtil.isNotEmpty(region_code), SchBasePoint::getRegion_code, region_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.EMPTY_PALLETS.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicleType)
.eq(SchBasePoint::getIs_used, true)
// 修复18添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
if (CollectionUtils.isEmpty(schBasePoints)) {
schBasePoints = pointMapper.selectList(Wrappers.lambdaQuery(SchBasePoint.class)
.eq(SchBasePoint::getIs_lock, false)
.isNotNull(SchBasePoint::getVehicle_code)
.eq(SchBasePoint::getPoint_status, GoodsEnum.EMPTY_PALLETS.getValue())
.eq(SchBasePoint::getCan_vehicle_type, vehicleType)
.eq(SchBasePoint::getIs_used, true)
// 修复19添加行锁+LIMIT 1
.last("LIMIT 1 FOR UPDATE"));
}
if (schBasePoints.size() == 0) {
return null;
}
SchBasePoint schBasePoint = schBasePoints.get(0);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointMapper.updateById(schBasePoint);
return schBasePoint;
}
}

View File

@@ -45,4 +45,32 @@ public enum TaskStatus {
public void setDesc(String desc) {
this.desc = desc;
}
/**
* 根据code查找name
* @param code 状态码
* @return 状态名称
*/
public static String getNameByCode(String code) {
for (TaskStatus status : TaskStatus.values()) {
if (status.getCode().equals(code)) {
return status.getName();
}
}
return null;
}
/**
* 根据name查找code
* @param name 状态名称
* @return 状态码
*/
public static String getCodeByName(String name) {
for (TaskStatus status : TaskStatus.values()) {
if (status.getName().equals(name)) {
return status.getCode();
}
}
return null;
}
}

View File

@@ -131,7 +131,7 @@ public class GHCQLTask extends AbstractTask {
//任务创建后锁住终点
SchBasePoint nextPoint = pointService.getById(task.getPoint_code2());
nextPoint.setIng_task_code(task.getTask_code());
pointService.updateById(point);
pointService.updateById(nextPoint);
}
/**

View File

@@ -93,10 +93,10 @@ public class BlankingTask extends AbstractTask {
TaskUtils.setUpdateByAcs(task);
taskService.updateById(task);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointService.updateById(schBasePoint);
//锁定功能已经写在查询中,防止出现相同点位
// schBasePoint.setIs_lock(true);
// PointUtils.setUpdateByAcs(schBasePoint);
// pointService.updateById(schBasePoint);
}
}

View File

@@ -74,9 +74,10 @@ public class MtTask extends AbstractTask {
TaskUtils.setUpdateByAcs(task);
taskService.updateById(task);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointService.updateById(schBasePoint);
//锁定功能已经写在查询中,防止出现分配到相同点位,因此注释
// schBasePoint.setIs_lock(true);
// PointUtils.setUpdateByAcs(schBasePoint);
// pointService.updateById(schBasePoint);
}
}

View File

@@ -84,9 +84,10 @@ public class RackTask extends AbstractTask {
task.setTask_status(TaskStatus.CREATED.getCode());
TaskUtils.setUpdateByAcs(task);
taskService.updateById(task);
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointService.updateById(schBasePoint);
//锁定功能已经写在查询中,防止出现分配到相同点位,因此注释
// schBasePoint.setIs_lock(true);
// PointUtils.setUpdateByAcs(schBasePoint);
// pointService.updateById(schBasePoint);
}
}

View File

@@ -105,7 +105,7 @@ public class ProcessingSMTTask extends AbstractTask {
NoticeTypeEnum.WARN.getCode());
continue;
}
SchBasePoint schBasePoint = schBasePointService.selectGroundByRegionCode(targetRegionCode, GoodsEnum.OUT_OF_STOCK.getValue());
SchBasePoint schBasePoint = schBasePointService.selectGroundByRegionCode(targetRegionCode, GoodsEnum.OUT_OF_STOCK.getValue(),true);
if (ObjectUtil.isEmpty(schBasePoint)) {
task.setRemark("未找到所需点位!");
taskService.updateById(task);
@@ -123,7 +123,6 @@ public class ProcessingSMTTask extends AbstractTask {
taskService.updateById(task);
//更新点位
schBasePoint.setIs_lock(true);
PointUtils.setUpdateByAcs(schBasePoint);
pointService.updateById(schBasePoint);
}