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

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

该部分内容较为基础,大多为简单的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);
        }
    }
}
相关推荐
子兮曰15 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!15 小时前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰15 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
俊昭喜喜里15 小时前
java中的继承和多态的区别
java
小羊没烦恼!15 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝15 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕15 小时前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码16 小时前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖16 小时前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时16 小时前
01-06-A-JVM排查实战详解
java·jvm