zoukankan      html  css  js  c++  java
  • 【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); } } }




    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    小学四则运算APP 最后阶段
    小学四则运算APP 第三阶段冲刺-第一天
    小学四则运算APP 第二阶段冲刺-第五天
    小学四则运算APP 第二次冲刺 第四天
    小学四则运算APP 第二阶段冲刺-第三天
    小学四则运算APP 第二次冲刺-第二天
    小学四则运算APP 第二个冲刺 第一天
    小学四则运算APP 第一个冲刺 第八天
    小学四则运算APP 第一个冲刺 第七天
    小学四则运算APP 第一个冲刺阶段 第六天
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4638052.html
Copyright © 2011-2022 走看看