现在有一张 菜单表 和 一张 资源表 ,表结构如下:
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); //删除菜单
resourcesDao.deleteResourceByMenuId(id); //删除资源
}
递归调用删除菜单,数据库操作过于频繁,当然这只是一个菜单表,数据量小,没什么影响。
对于数据库操作过于频繁,你可能已经想到了解决方法:批量删除,请看下面
常见的递归写法二
#### Java语法
public void deleteMenuById(Long id) {
List<Long> idList = new ArrayList(); //要删除的菜单ID列表
querySubMenuId(id, idList); //idList属于地址传递哦
menuDao.deleteMenusById(idList); //批量删除菜单
resourcesDao.deleteResourcesByMenuId(idList); //批量删除资源
}
private void querySubMenuId(Long id, List<Long> idList) {
List<Long> sub = menuDao.querySubMenuIdByPid(id); //查找子菜单
for(Long subid : sub) {
idList.add(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) { //出队列,没有代表所有子菜单全部查完了
idList.add(menuId); //要删除的菜单ID
queue.addAll(menuDao.querySubMenuIdByPid(menuId)); //查询子菜单ID 并 入对列
}
menuDao.deleteMenusById(idList); //批量删除菜单
resourcesDao.deleteResourcesByMenuId(idList); //批量删除资源
}
有没有发现,我们已经成功的把递归去掉了,结合 队列 实现了 多级菜单 删除功能。
小结
可能有人会有 疑问 ,有没有办法把查询子菜单的 SQL 也优化成:一条SQL可以把菜单下面的所有子菜单全部查询出来,不再循环查询呢?
答案是有的,这篇文章就不介绍了,我们的目标是 去掉递归 用法,现在已经实现了。后续再单独介绍(“进制”级别表示法)。
长路漫漫,每天坚持至少一篇,写的好的话,还请多多宣传多多留言,记的『 关注 』我哦!