【DRP】删除递归树的操作
正如图呈现的树结构。本文从任意节点删除树形结构。提供解决方案
图中,不包括其他结点的是叶子结点。包括其他结点的是父结点,即不是叶子结点。
一 本文的知识点:
(1)递归调用:
由于待删除的结点的层次是不确定的,假设是叶子结点则能够直接获取id直接删除,如:北京中医医院、华北区。假设待删除的结点是父结点,则须要继续向下查询,依次遍历出其子结点,从下往上依次删除,如‘华北区’。因此我们使用递归调用。
(2)保证事务的原子性
如果待删除的结点是‘华北区’。则相当于删除了3条信息(华北区、北京市、北京中医医院)。通常觉得同一时候删除多条数据,是具有原子性的。
删除100条信息,相当于一个事务。要么一起删除。要么都不删除。
事务控制,表现为双方面:一个是递归删除过程中採用一个Connection(同一时候防止递归中循环调用导致Connection效率不高)。还有一个是设置手动提交。
(3)异常是throws ?还是catch?
主方法delClientOrRegion为public 採用try…catch……finally打印堆栈中的错误信息。主方法中调用的方法。如:recursionDelNode、getChildren、modifyIsLeafField。均为private仅供方法内部调用。同一时候採用throws
SQLException抛出异常,而不是catch捕捉异常。
这是由于如果getChildren内部catch了错误,打印了堆栈信息。那么上面一层不知道它出错的话。因此就不会事务回滚。
因此建议内部抛出异常throws
SQLException,外部使用捕获异常try catch
(4)树的几种设计方式
1)不带冗余字段,id主键,pid父结点主键
2)带冗余字段。id、pid、isleaf是否为叶子、childrencount孩子结点的数目
3)採用固定的字符串00010010001
00全部分销商
01华北区
001北京市
0001北京中医医院
(本数据库设计採用:id主键、pid父结点主键、is_leaf是否为叶子结点)
(5)业务逻辑解析,如果待删除结点为‘北京市’
1)保存父结点对象。即:获取‘北京市’的父结点‘华北区’的id。
2)递归删除树结点。即:删除‘北京市’同一时候还要删除其孩子结点‘北京中医医院’。
删除的顺序也是有要求的,先删除孩子,后删除父亲。即先删除‘北京中医医院’。后删除‘北京市’。这一点在递归代码中有所体现。
3)假设父结点下没有子结点,则改动为叶子结点。
即:假设‘华北区’没有孩子。则须要设置‘华北区’为叶子结点。
二 部分代码例如以下:
package com.bjpowernode.drp.basedata.manager; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import com.bjpowernode.drp.basedata.domain.AimClient;
import com.bjpowernode.drp.basedata.domain.Client;
import com.bjpowernode.drp.util.Constants;
import com.bjpowernode.drp.util.DbUtil;
import com.bjpowernode.drp.util.IdGenerator;
import com.bjpowernode.drp.util.PageModel;
import com.bjpowernode.drp.util.datadict.domain.ClientLevel; /**
* 採用单例实现
* @author Administrator
*
*/
public class ClientManager { private static ClientManager instance = new ClientManager(); private ClientManager() {} public static ClientManager getInstance() {
return instance;
} /**
* 删除分销商或区域
* @param id
*/
public void delClientOrRegion(int id) {
Connection conn = null;
try {
conn = DbUtil.getConnection();
//手动控制事务的开启
DbUtil.beginTransaction(conn); //保存父节点对象
Client currentNode = findClientOrRegionById(id); //递归删除树节点
recursionDelNode(conn, id); //假设父节点下没有子节点
if (getChildren(conn, currentNode.getPid()) == 0) {
//改动为叶子
modifyIsLeafField(conn, currentNode.getPid(), Constants.YES);
}
//提交事务
DbUtil.commitTransaction(conn);
}catch(Exception e) {
//假设出错则打印堆栈信息
e.printStackTrace();
//事务回滚
DbUtil.rollbackTransaction(conn);
}finally {
//事务重置
DbUtil.resetConnection(conn);
//关闭数据库连接
DbUtil.close(conn);
}
}
/**
* 递归删除
* @param conn
* @param id
*/
private void recursionDelNode(Connection conn, int id)
throws SQLException {
//依据
String sql = "select * from t_client where pid=? ";
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
while (rs.next()) {
//假设是不叶子节点。则递归调用
if (Constants.NO.equals(rs.getString("is_leaf"))) {
recursionDelNode(conn, rs.getInt("id"));
}
//假设是叶子节点。则直接删除
delNode(conn, rs.getInt("id"));
}
//删除自身
delNode(conn, id);
}finally {
DbUtil.close(rs);
DbUtil.close(pstmt);
}
}
/**
* 取得指定节点的孩子数目
* @param conn
* @param id
* @return
*/
private int getChildren(Connection conn, int id)
throws SQLException {
//sql语句通过孩子pid的个数,推断是否为叶子节点
String sql = "select count(*) as c from t_client where pid=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
int count = 0;
try {
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
rs.next();
count = rs.getInt("c");
}finally {
DbUtil.close(rs);
DbUtil.close(pstmt);
}
return count;
}
/**
* 改动isLeaf字段
* @param conn
* @param id
* @param leaf Y/N
*/
private void modifyIsLeafField(Connection conn, int id, String leaf)
throws SQLException {
//假设待删除的节点的父节点没有其它孩子节点,则设置为叶子状态
String sql = "update t_client set is_leaf=? where id=? ";
PreparedStatement pstmt = null;
try {
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, leaf);
pstmt.setInt(2, id);
pstmt.executeUpdate();
} finally {
DbUtil.close(pstmt);
}
}
}
版权声明:本文博客原创文章。博客,未经同意,不得转载。
【DRP】删除递归树的操作的更多相关文章
- 递归树处理,配合vue的vueTreeselect组件使用
在项目中经常会使用到tree,并且需要对递归树进行操作. 在vue项目中,使用vue-treeselect插件(https://vue-treeselect.js.org/) 使用中遇到的问题: 1. ...
- 递归删除资源树 Ztree
前言 最近项目里有这么一个需求:现在有一个用Ztree编写的资源树,当删除资源树的某个节点时,则将此节点下面的所有节点全部删除,这里显然就用到了递归:若此节点被删除后无其它的兄弟节点了,我们还需要将其 ...
- ext 树节点操作
ext 树节点操作 tree :树 node:节点 1.全部展开 tree.expandAll(); 2.全部收缩 tree.collapseAll(); 3.得到父节点 node.parent ...
- react封装组织架构递归树
想用react实现一个递归树,但一些框架里面的有些不符合需求,于是自己写了个,功能比较简单,欢迎批评指正.. react实现这样一个组织架构递归树,下级部门的收起和展开,点击部门名称时请求接口获取下级 ...
- hdu 2871 线段树(各种操作)
Memory Control Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- MIT6.006Lec03:插入排序,归并排序,递归树
MIT6.006是算法导论课,Lec03主要讲插入排序,归并排序,以及分析方法(递归树)等. 插入排序,可以分为线性插入排序.二分插入排序,区别在于当把数组中某元素插入到前面的有序列表中时,前者遍历, ...
- 【整理】iview Tree数据格式问题,无限递归树处理数据
iview Tree数据格式问题,无限递归树处理数据 https://juejin.im/post/5b51a8a4e51d455d6825be20
- SUSE Ceph 增加节点、减少节点、 删除OSD磁盘等操作 - Storage6
一.测试环境描述 之前我们已快速部署好一套Ceph集群(3节点),现要测试在现有集群中在线方式增加节点 如下表中可以看到增加节点node004具体配置 主机名 Public网络 管理网络 集群网络 说 ...
- C/C++深度优先搜索(递归树模拟)
//C++深度优先搜索(递归树模拟) #define _CRT_SECURE_NO_WARNINGS #include <iostream> #define MAX_N 1000 usin ...
随机推荐
- Cocos2dx引擎10-事件派发
本文介绍Cocos2dx事件(以下简称Event)处理机制中的事件分发模块,在Event发生后,进过一系列处理,最后将会分发Event: 1.dispatchEvent& dispatchTo ...
- sql为数字添加千分位(也就是钱的格式)
感觉这个东西在项目中用得挺多的,之前在前台页面是用正则来处理,现在由于是数据查询,所以直接在查出数据的时候将其转为指定的千分位格式,省的前台再处理,不讲原理,因为我也看不懂,不过会用就行了,在网上找了 ...
- JavaScript快速入门(四)——JavaScript函数
函数声明 之前说的三种函数声明中(参见JavaScript快速入门(二)——JavaScript变量),使用Function构造函数的声明方法比较少见,我们暂时不提.function func() { ...
- poj1011Sticks
传说中的poj必做50题之中的一个-- 这是个传说中的搜索, 一開始以为, 仅仅要棒子加起来等于如果的原始长度, 那么这几根选择的棒子就不用管了, 结果卡在第一个例子-- 看了一下,发现, 代码把1, ...
- Swift - 点击输入框外部屏幕关闭虚拟键盘
我们如果把文本框的Return Key设置成Done,然后在storyboard中将文本框的Did End On Exit事件在代码里进行关联.同时关联代码里调用文本框的resignFirstResp ...
- HDU 1269 迷宫城堡(强连通)
HDU 1269 迷宫城堡 pid=1269" target="_blank" style="">题目链接 题意:中文题 思路:强连通模板题 代 ...
- Android设计中的.9.png与Android Studio中的设置
在Android的设计过程中,为了适配不同的手机分辨率,图片大多需要拉伸或者压缩,这样就出现了可以任意调整大小的一种图片格式“.9.png”.这种图片是用于Android开发的一种特殊的图片格式,它的 ...
- IOS不用AutoLayout也能实现自己主动布局的类(3)----MyRelativeLayout横空出世
对于IOS开发人员来说,在自己主动布局出现前仅仅能通过计算和设置frame的值来处理.这样设置位置时就会出现非常多硬编码,同一时候在屏幕旋转和不同屏幕之间适配时须要编码又一次调整位置和尺寸,我们也能够 ...
- tar.gz文件命名和压缩解压方法
tar.gz文件命名 tar这是文件打成一个包,无压缩; gz同gzip标记的包.tar文件压缩; 所以它成为一个.tar.gz档 压缩 # tar cvfz backup.tar.gz /xxx/ ...
- POJ 1742 hdu 2844 Coins
题目链接:http://poj.org/problem?id=1742 http://acm.hdu.edu.cn/showproblem.php?pid=2844 题目分类:动态规划 代码: #in ...