SpringBoot业务层开发常见问题

1. 目录层级数据返回问题

获取到一堆数据,诸如这种,需要向前端返回带层级的数据,从数据库获取数据的方式为递归sql:

with recursive t1 as(
	select * from course_category where id = '1'
	union ALL
	select t2.* from course_category t2 join t1 where t1.id = t2.parentid
)
select * from t1

需要向前端返回的数据为List<CourseCategoryTreeDto>

CourseCategoryTreeDto:

包含当前子节点的列表的父节点信息和一个子节点列表:

对这些数据应该进行如下操作:

@Override
    public List<CourseCategoryTreeDto> queryTreeNodes(String id) {
        List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes(id);
        //先将list转成map,key是节点的id,value是CourseCategoryTreeDto对象,目的就是方便从map中获取节点,对map进行过滤,不需要根节点1,也即.filter()
        Map<String, CourseCategoryTreeDto> idDtoMap = courseCategoryTreeDtos.stream().filter(item -> !item.getId().equals(id)).collect(Collectors.toMap(CourseCategory::getId, value -> value, (key1, key2) -> key2));
        //new出需要返回的list
        List<CourseCategoryTreeDto> categoryList = new ArrayList<>();
        //从头遍历List<CourseCategoryTreeDto>,一边遍历一边找子节点放在父节点的childrenTreeNodes属性中
        courseCategoryTreeDtos.stream().filter(item -> !item.getId().equals(id)).forEach(item -> {
            if(item.getParentid().equals(id)){
                categoryList.add(item);
            }
            CourseCategoryTreeDto courseCategoryTreeDto = idDtoMap.get(item.getParentid());
            if(courseCategoryTreeDto!=null){
                if(courseCategoryTreeDto.getChildrenTreeNodes() == null){
                    courseCategoryTreeDto.setChildrenTreeNodes(new ArrayList<>());
                }
                courseCategoryTreeDto.getChildrenTreeNodes().add(item);
            }

        });

        return categoryList;
    }

使用stream操作,支持多级

2. 数据库多线程中的乐观锁

//抢占任务 使用数据库的锁
                    boolean b = mediaFileProcessService.startTask(taskId);
                    if (!b) {
                        return;
                    }

视频任务处理场景:通过在status字段上加上 “处理中” 情况,在开始,将该字段的status字段进行更新的处理中,这样其它线程就抢占不到锁,

SQL语句:

update media_process m set m.status='4' where (m.status='1' or m.status='3') and m.fail_count<3 and m.id=#{id}

基于数据库实现分布锁

利用数据库主键唯一性的特点,或利用数据库唯一索引、行级锁的特点,多个线程同时去更新相同的记录,谁更新成功谁就抢到锁。

3.多线程问题

//启动size个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(size);
        //计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);//可以使线程阻塞

CountDownLatch可以控制在一段函数中使用多线程执行任务时,可以阻塞当前函数,减为0时,函数结束。

countDownLatch.countDown();

保底策略

//等待,给一个充裕的超时时间,防止无限等待,到达超时时间还没有处理完成则结束任务
        countDownLatch.await(30, TimeUnit.MINUTES);

4.xxljob

1.任务执行器根据配置的调度中心的地址,自动注册到调度中心

2.达到任务触发条件,调度中心下发任务

3.执行器基于线程池执行任务,并把执行结果放入内存队列中、把执行日志写入日志文件中

4.执行器消费内存队列中的执行结果,主动上报给调度中心

5.当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行器读取任务日志文件并返回日志详情

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay/.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值