Explorar o código

优化合同段收藏文件夹创建逻辑,加锁

lvy hai 1 semana
pai
achega
c680837db8

+ 32 - 16
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ContractCollectFolderServiceImpl.java

@@ -17,12 +17,14 @@ import org.springblade.manager.service.IContractCollectFolderService;
 import org.springblade.manager.service.IWbsTreeContractService;
 import org.springblade.manager.vo.ContractCollectFolderVO;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.Duration;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
@@ -70,23 +72,37 @@ public class ContractCollectFolderServiceImpl extends ServiceImpl<ContractCollec
         if (vo == null || StringUtil.isBlank(vo.getName())) {
             return false;
         }
-        long count = this.count(Wrappers.<ContractCollectFolder>lambdaQuery().eq(ContractCollectFolder::getType, 0).eq(ContractCollectFolder::getContractId, vo.getContractId())
-                .eq(ContractCollectFolder::getFolderName, vo.getName()).last(" limit 1"));
-        if (count > 0) {
-            throw new ServiceException("收藏夹名称重复");
-        }
-        deletedCache(vo.getContractId());
-        if (vo.getId() == null) {
-            ContractCollectFolder entity = new ContractCollectFolder();
-            entity.setContractId(vo.getContractId());
-            entity.setCreateUser(AuthUtil.getUserId());
-            entity.setType(0);
-            entity.setId(SnowFlakeUtil.getId());
-            entity.setFolderName(vo.getName());
-            return this.save(entity);
+        String lockKey = "blade-manager:lock:contract:collectFolder:" + vo.getContractId();
+        String lockValue = UUID.randomUUID().toString();
+        try {
+            // 尝试获取分布式锁,设置过期时间防止死锁
+            Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, Duration.ofSeconds(30));
+            if (lockAcquired == null || !lockAcquired) {
+                throw new ServiceException("系统繁忙,请稍后再试");
+            }
+            long count = this.count(Wrappers.<ContractCollectFolder>lambdaQuery().eq(ContractCollectFolder::getType, 0).eq(ContractCollectFolder::getContractId, vo.getContractId())
+                    .eq(ContractCollectFolder::getFolderName, vo.getName()).ne(vo.getId() != null, ContractCollectFolder::getId, vo.getId()).last(" limit 1"));
+            if (count > 0) {
+                throw new ServiceException("收藏夹名称重复");
+            }
+            deletedCache(vo.getContractId());
+            if (vo.getId() == null) {
+                ContractCollectFolder entity = new ContractCollectFolder();
+                entity.setContractId(vo.getContractId());
+                entity.setCreateUser(AuthUtil.getUserId());
+                entity.setType(0);
+                entity.setId(SnowFlakeUtil.getId());
+                entity.setFolderName(vo.getName());
+                return this.save(entity);
+            }
+            return this.update(Wrappers.<ContractCollectFolder>lambdaUpdate()
+                    .set(ContractCollectFolder::getFolderName, vo.getName())
+                    .eq(ContractCollectFolder::getId, vo.getId()));
+        } finally {
+            // 释放分布式锁
+            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
+            redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Collections.singletonList(lockKey), lockValue);
         }
-        return this.update(Wrappers.<ContractCollectFolder>lambdaUpdate().set(ContractCollectFolder::getFolderName, vo.getName())
-                .eq(ContractCollectFolder::getId, vo.getId()));
     }
 
     @Override