最近在实现博客系统的markdown文章导入功能的时候,遇到了多并发的问题,主要是导入插件是element-plus提供的,然后进行批量上传的时候,实际上是同一时间发送多次上传请求,也就出现了多并发的情况。本以为使用synchronized就可以处理的,结果还是一个知识点!!!

相关代码

    public  MlogTags saveIfAbsent(@NotNull(message = "标签名称不能为空") String tagName) {
	//从数据库获取标签,判断标签是否存在,如果不存在就新增,否则返回存在的标签信息   
 	Optional<MlogTags> tags = getByName(tagName);
        MlogTags tag;
        if (tags.isEmpty()) {
            tag = new MlogTags();
            tag.setTag(tagName);
            tag.setColor(Constant.DEFAULT_COLOR);
            save(tag);
        } else {
            tag = tags.get();
        }
        return tag;
    }

上面的代码会导致当多并发出现的时候,就会出现save方法还未执行,另一个请求已经执行完getByName这个方法,然后就会保存多份相同的标签。

考虑到是博客系统,直接使用synchronized加锁即可。

//加上synchronized
   public synchronized MlogTags saveIfAbsent(@NotNull(message = "标签名称不能为空") String tagName) {
	//从数据库获取标签,判断标签是否存在,如果不存在就新增,否则返回存在的标签信息   
 	Optional<MlogTags> tags = getByName(tagName);
        MlogTags tag;
        if (tags.isEmpty()) {
            tag = new MlogTags();
            tag.setTag(tagName);
            tag.setColor(Constant.DEFAULT_COLOR);
            save(tag);
        } else {
            tag = tags.get();
        }
        return tag;
    }

本以为加上就可以搞定了,但是问题依旧存在,锁没有生效。

具体原因

因为我是其他的方法在调用saveIfAbsent这个方法。因为导入操作要保证一致性,所以开启了事务管理,spring事务管理会在方法执行前生成一个代理类,通过代理类去执行,所以导致每次加锁,加的是每次生成的代理类上面的代码块。


    @Override
    @Transactional(rollbackFor = Exception.class)//开启aop事务管理
    public  Boolean importMarkdown(MultipartFile file, HttpServletRequest request) {
  	//解析md生成文章对象
         ArticleDTO article = parseMdFile(file);
        //保存文章标签信息
        saveIfAbsent(article.getTag());
	......其他业务代码
        return true;
    }

处理方式

在开启事务前加锁即可,即调用importMarkdown方法之前,进行加锁即可

    synchronized (this) {
             articleService.importMarkdown(file, request);
        }

参考资料

Spring事务管理下synchronized锁失效问题

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐