现在有一张菜单表 和 一张资源表,表结构如下:
system_menu(id,pid,title,...) //id-菜单ID pid-上级菜单ID title-菜单名称 system_menu_resource(id,menu_id,title,...) //id-资源ID menu_id-菜单ID title资源名称
需求如下:
请删除ID=1000的菜单及其下面的所有子菜单 和 关联的所有资源
是不是有写过类似的案例,请问你首先想到的解决方案是不是通过递归调用来实现业务逻辑呢?
常见的递归写法一
#### Java语法 public void deleteMenuById(Long id) { List<Long> subMenuIdList = menuDao.querySubMenuIdByPid(id); //查找子菜单ID列表 for(Long subMenuId : subMenuIdList) { deleteMenuById(subMenuId); //递归调用删除子菜单的数据 } menuDao.deleteMenuById(id); //删除菜单 re(id); //删除资源 }
递归调用删除菜单,数据库操作过于频繁,当然这只是一个菜单表,数据量小,没什么影响。
对于数据库操作过于频繁,你可能已经想到了解决方法:批量删除,请看下面
难道是
常见的递归写法二
#### Java语法 public void deleteMenuById(Long id) { List<Long> idList = new ArrayList(); //要删除的菜单ID列表 querySubMenuId(id, idList); //idList属于地址传递哦 menuDao.deleteMenusById(idList); //批量删除菜单 re(idList); //批量删除资源 } private void querySubMenuId(Long id, List<Long> idList) { List<Long> sub = menuDao.querySubMenuIdByPid(id); //查找子菜单 for(Long subid : sub) { idLi(subid); //添加到列表中 querySubMenuId(subid); //递归调用查找子菜单 } }
看到这里,是不是感觉很好了,效率很高了呢,没有什么优化的方案了?
接下来 我们看一下如何去掉递归调用查询数据
请求支援
推荐的写法
#### Java语法 public void deleteMenuById(Long id) { List<Long> idList = new ArrayList<>(); //需要删除的菜单ID列表 Queue<Long> queue = new LinkedList<>(); //临时队列 queue.offer(id); //先把最上面的菜单ID放入对列 Long menuId = null; while((menuId = ids.poll()) != null) { //出队列,没有代表所有子菜单全部查完了 idLi(menuId); //要删除的菜单ID queue.addAll(menuId)); //查询子菜单ID 并 入对列 } menuDao.deleteMenusById(idList); //批量删除菜单 re(idList); //批量删除资源 }
有没有发现,我们已经成功的把递归去掉了,结合队列实现了多级菜单删除功能。
小结
可能有人会有疑问,有没有办法把查询子菜单的SQL也优化成:一条SQL可以把菜单下面的所有子菜单全部查询出来,不再循环查询呢?
答案是有的,这篇文章就不介绍了,我们的目标是去掉递归用法,现在已经实现了。后续再单独介绍("进制"级别表示法)。
长路漫漫,每天坚持至少一篇,写的好的话,还请多多宣传多多留言,记的『关注』我哦!