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

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

该部分内容较为基础,大多为简单的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);
        }
    }
}
相关推荐
用户5611610232731 小时前
量化笔记程序代码分析,逐笔数据、五档快照和分钟行情代码分析
数据库
房开民1 小时前
通俗总结 Octree(八叉树)
java·服务器·数据库
豆角焖肉1 小时前
SpringBoot 集成腾讯 AI 人脸识别
人工智能·spring boot·后端·人脸识别·腾讯 ai·base64 图片
付威20231 小时前
如果你想拥有自己的 Agent,为什么值得从 rpi 开始
后端
木头科技1 小时前
【AI 工程化第十五篇】Spring AI 流式输出高并发性能优化实战:SSE、背压、限流、缓存与灰度发布
人工智能·spring·性能优化
星云低代码开发平台1 小时前
AI 连接器运行健康度:指标、异常恢复和联调清单
大数据·运维·网络·数据库·人工智能·mcp
2302_805771071 小时前
Day23:POM设计模式(封装)
java·开发语言·设计模式
SL_staff1 小时前
APS降本增效的关键:在JVS中实现‘人-机-料-法-环’全要素耦合调度
java·github·全栈
十年Java程序媛1 小时前
Java String、StringBuilder、StringBuffer 底层原理|字符串拼接性能与线程安全
java·开发语言·spring boot·安全·面试
可乐ea1 小时前
2000 个智能体把 Agent 重写成 Rust:编排流水线拆解
开发语言·后端·rust·多智能体协作·ai编程助手·智能体编排·rust重写