|
|
@@ -23,6 +23,7 @@ import org.dromara.yingpaipay.api.erp.CommonErpClientService;
|
|
|
import org.dromara.yingpaipay.api.erp.domain.vo.CommonErpClientVo;
|
|
|
import org.springframework.cache.annotation.Cacheable;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
@@ -203,38 +204,84 @@ public class SysEmployeeServiceImpl implements ISysEmployeeService, EmployeeServ
|
|
|
|
|
|
/**
|
|
|
* 修改员工(仅更新非 null 字段,支持部分更新)
|
|
|
+ * 使用数据库行锁(FOR UPDATE)解决 TOCTOU 竞态条件
|
|
|
*/
|
|
|
+ @Transactional
|
|
|
@Override
|
|
|
public Boolean updateByBo(SysEmployeeBo bo) {
|
|
|
- SysEmployee update = MapstructUtils.convert(bo, SysEmployee.class);
|
|
|
- LambdaUpdateWrapper<SysEmployee> wrapper = new LambdaUpdateWrapper<>();
|
|
|
- wrapper.eq(SysEmployee::getId, update.getId());
|
|
|
- if (ObjectUtil.isNotNull(update.getName())) {
|
|
|
- wrapper.set(SysEmployee::getName, update.getName());
|
|
|
+ baseMapper.selectOne(
|
|
|
+ Wrappers.lambdaQuery(SysEmployee.class)
|
|
|
+ .eq(SysEmployee::getId, bo.getId())
|
|
|
+ .last("FOR UPDATE")
|
|
|
+ );
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(bo.getAuthClientFRowIDs())) {
|
|
|
+ Set<String> newRowIds = Arrays.stream(bo.getAuthClientFRowIDs().split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ if (!newRowIds.isEmpty()) {
|
|
|
+ List<SysEmployee> otherEmployees = baseMapper.selectList(
|
|
|
+ Wrappers.lambdaQuery(SysEmployee.class)
|
|
|
+ .select(SysEmployee::getId, SysEmployee::getAuthClientFRowIDs)
|
|
|
+ .ne(SysEmployee::getId, bo.getId())
|
|
|
+ .isNotNull(SysEmployee::getAuthClientFRowIDs)
|
|
|
+ .ne(SysEmployee::getAuthClientFRowIDs, "")
|
|
|
+ .last("FOR UPDATE")
|
|
|
+ );
|
|
|
+ Set<String> conflictRowIds = new HashSet<>();
|
|
|
+ for (SysEmployee other : otherEmployees) {
|
|
|
+ if (StringUtils.isBlank(other.getAuthClientFRowIDs())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ for (String id : other.getAuthClientFRowIDs().split(",")) {
|
|
|
+ String trimmed = id.trim();
|
|
|
+ if (newRowIds.contains(trimmed)) {
|
|
|
+ conflictRowIds.add(trimmed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!conflictRowIds.isEmpty()) {
|
|
|
+ Map<String, CommonErpClientVo> infoMap = commonErpClientService.selectInfoByFRowIDs(new ArrayList<>(conflictRowIds));
|
|
|
+ String conflictNames = conflictRowIds.stream()
|
|
|
+ .map(id -> {
|
|
|
+ CommonErpClientVo vo = infoMap.get(id);
|
|
|
+ return vo != null ? vo.getName() : id;
|
|
|
+ })
|
|
|
+ .collect(Collectors.joining("、"));
|
|
|
+ throw new ServiceException("以下客户已被其他员工授权,请先取消后再操作:" + conflictNames);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getPhone())) {
|
|
|
- wrapper.set(SysEmployee::getPhone, update.getPhone());
|
|
|
+
|
|
|
+ if (bo.getId() != null) {
|
|
|
+ CacheUtils.evict(CacheNames.SYS_EMPLOYEE_NAME, bo.getId());
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getAvatar())) {
|
|
|
- wrapper.set(SysEmployee::getAvatar, update.getAvatar());
|
|
|
+
|
|
|
+ LambdaUpdateWrapper<SysEmployee> wrapper = new LambdaUpdateWrapper<>();
|
|
|
+ wrapper.eq(SysEmployee::getId, bo.getId());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getName())) {
|
|
|
+ wrapper.set(SysEmployee::getName, bo.getName());
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getStatus())) {
|
|
|
- wrapper.set(SysEmployee::getStatus, update.getStatus());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getPhone())) {
|
|
|
+ wrapper.set(SysEmployee::getPhone, bo.getPhone());
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getAuthClientFRowIDs())) {
|
|
|
- wrapper.set(SysEmployee::getAuthClientFRowIDs, update.getAuthClientFRowIDs());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getAvatar())) {
|
|
|
+ wrapper.set(SysEmployee::getAvatar, bo.getAvatar());
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getWechatOpenid())) {
|
|
|
- wrapper.set(SysEmployee::getWechatOpenid, update.getWechatOpenid());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getStatus())) {
|
|
|
+ wrapper.set(SysEmployee::getStatus, bo.getStatus());
|
|
|
}
|
|
|
- if (ObjectUtil.isNotNull(update.getWechatUnionid())) {
|
|
|
- wrapper.set(SysEmployee::getWechatUnionid, update.getWechatUnionid());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getAuthClientFRowIDs())) {
|
|
|
+ wrapper.set(SysEmployee::getAuthClientFRowIDs, bo.getAuthClientFRowIDs());
|
|
|
}
|
|
|
- boolean result = baseMapper.update(null, wrapper) > 0;
|
|
|
- if (result && bo.getId() != null) {
|
|
|
- CacheUtils.evict(CacheNames.SYS_EMPLOYEE_NAME, bo.getId());
|
|
|
+ if (ObjectUtil.isNotNull(bo.getWechatOpenid())) {
|
|
|
+ wrapper.set(SysEmployee::getWechatOpenid, bo.getWechatOpenid());
|
|
|
+ }
|
|
|
+ if (ObjectUtil.isNotNull(bo.getWechatUnionid())) {
|
|
|
+ wrapper.set(SysEmployee::getWechatUnionid, bo.getWechatUnionid());
|
|
|
}
|
|
|
- return result;
|
|
|
+ return baseMapper.update(null, wrapper) > 0;
|
|
|
}
|
|
|
|
|
|
/**
|