【智能协图云图库|第七天】 空间模块初始化

本部分内容主要来源于鱼皮智能协图云图库部分,并在笔者个人项目学习的基础上进行扩展衍生。由于项目开发文档已经足够详细,因此这里只记录要点。

该部分内容较为基础,大多为简单的CRUD。因此熟悉业务流程才是重点。

需求分析

设想:创建用户独享的空间服务(可作为云盘)------>衍生具体功能------>衍生问题思考

功能------问题:

1)用户能创建空间------>创建空间的条件,私有空间的权限,空间的额度等

2)管理员管理空间------>对于用户空间是不是能随意修改,管理员权限范围等

理解空间:

和公共空间一样本质就是张表。在我们没有设计公共空间的时候,picture表本身就代表着公共空间。这里也可以采用在picture表添加字段的形式将picture划分为公共空间与私有空间。然而由于这里对公共空间与私有空间的逻辑处理有较大差别,因此专门设计单独的空间表。

在有公共空间与私有空间的划分后,图片归属于空间,因此也要对图片加字段来分辨图片处于公共空间or私有空间。

sql 复制代码
ALTER TABLE picture
    ADD COLUMN spaceId  bigint  null comment '空间 id(为空表示公共空间)';


CREATE INDEX idx_spaceId ON picture (spaceId);

后端开发

空间模块的初步建立,增删改查操作流程------>有空间模块后对图片模块的增删改查加入条件控制

------>完善空间模块级别限额等细节控制

这里的新知识点主要是用户创建私有空间

java 复制代码
@Resource
private TransactionTemplate transactionTemplate;

@Override
public long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
    
    Space space = new Space();
    BeanUtils.copyProperties(spaceAddRequest, space);
    
    if (StrUtil.isBlank(spaceAddRequest.getSpaceName())) {
        space.setSpaceName("默认空间");
    }
    if (spaceAddRequest.getSpaceLevel() == null) {
        space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
    }
    
    this.fillSpaceBySpaceLevel(space);
    
    this.validSpace(space, true);
    Long userId = loginUser.getId();
    space.setUserId(userId);
    
    if (SpaceLevelEnum.COMMON.getValue() != spaceAddRequest.getSpaceLevel() && !userService.isAdmin(loginUser)) {
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限创建指定级别的空间");
    }
    
    String lock = String.valueOf(userId).intern();
    synchronized (lock) {
        Long newSpaceId = transactionTemplate.execute(status -> {
            boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).exists();
            ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户仅能有一个私有空间");
            
            boolean result = this.save(space);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
            
            return space.getId();
        });
        
        return Optional.ofNullable(newSpaceId).orElse(-1L);
    }
}

要点:

1.锁粒度为用户,为确保锁住的是同一个对象使用intern()

2.缩小事务粒度,避免释放锁后事务还未提交transactionTemplate.execute()

为避免intern不能及时释放数据,占用大量内存还可以使用ConcurrentHashMap

java 复制代码
Map<Long, Object> lockMap = new ConcurrentHashMap<>();

public long addSpace(SpaceAddRequest spaceAddRequest, User user) {
    Long userId = user.getId();
    Object lock = lockMap.computeIfAbsent(userId, key -> new Object());
    synchronized (lock) {
        try {
            
        } finally {
            
            lockMap.remove(userId);
        }
    }
}
相关推荐
曹牧20 小时前
Spring:@RequestMapping注解,匹配的顺序与上下文无关
java·后端·spring
daixin884820 小时前
cursor无法正常使用gpt5.5等模型解决方案
java·redis·cursor
zhoutongsheng20 小时前
C#怎么实现Swagger文档 C#如何在ASP.NET Core中集成Swagger自动生成API文档【框架】
jvm·数据库·python
WinterKay20 小时前
【开源】我写了一个轻量级本地数据库浏览工具,支持 MySQL/Redis 只读查询
数据库·mysql·开源
韦禾水21 小时前
记录一次项目部署到tomcat的异常
java·tomcat
曦月合一21 小时前
树莓派安装jdk、tomcat、vnc、谷歌浏览器开机自启等环境配置
java·tomcat·树莓派
阿丰资源21 小时前
SpringBoot+Vue实战:打造企业级在线文档管理系统
vue.js·spring boot·后端
Rust研习社21 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
此剑之势丶愈斩愈烈21 小时前
openssl 自建证书
java
面汤放盐21 小时前
何时使用以及何时不应使用微服务:没有银弹
java·运维·云计算