`
leaves615
  • 浏览: 3548 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

数据库中的树结构-JAVA设计-缓存

阅读更多

我们通常会在应用中碰到树形结构的内容,比如 文件夹/文件模型, 部门组织结构,目录树等等,通常在设计模式中叫做 compose 模式。

在数据库中常常这样表示: 我们以Catalog (分级目录) 为例子

Catalog (分级目录)

字段名称

字段

类型

备注

目录ID

catalog_id

varchar(36)

pk, not null

目录名称

catalog_name

varchar(50)

not null

父目录ID

parent_id

varchar(36)

fk

创建时间

create_datetime

datetime

not null

目录描述

description

varchar(200)

 


我们考虑在数据库中一次将所有数据读入内存,然后在内存中生成一个Tree,这样可以减少数据库的访问,增加性能,并且只有的数据方式改变的时候,全部重新从数据库中生成Tree,否则一直保持在内存中。

我们使用标准的DAO模式先生成 POJO类(Catalog)和DAO类(CatalogDAO)。

然后我们建立相对通用的 Tree 和 TreeNode 类。

Tree.java

package com.humpic.helper.tree;

import java.util. * ;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public   abstract   class Tree {
   
protected   static Log log = LogFactory.getLog(Tree. class );

   
private Map treeNodeMaps =   new Hashtable();
   
private TreeNode root;

   
/**
     * root if it's parent is empty
    
*/
   
protected   void reload(List nodes) {
        log.info(
" tree will start reload all data " );
       
       
synchronized ( this ) {
           
// initialize
            treeNodeMaps.clear();
            root
=   null ;

            List treeNodes
=   new Vector(nodes.size());
           
for ( int i =   0 ; i < nodes.size(); i ++ ) {
                TreeNode node
=   this .transform(nodes.get(i)); // transform
                treeNodes.add(node);
                node.setTree(
this );
                treeNodeMaps.put(node.getNodeId(), node);
            }
           
           
for ( int i =   0 ; i < treeNodes.size(); i ++ ) {
                TreeNode node
= (TreeNode) treeNodes.get(i);
                String parentId
= node.getParentId();
               
if (this . isRootNode(node)) {
                    if (root ==   null ) {
                        root
= node;
                    }
else {
                        log.error(
" find more then one root node. ignore. " );
                    }

                }
else {
                   
TreeNode parent = (TreeNode) treeNodeMaps.get(parentId);
                   
if (parent !=   null ) {
                        parent.addChild(node);
                        node.setParent(parent);
                    }
else {
                        log.warn(
" node [id= "   + node.getNodeId() +   " ]: missing parent node. " );
                    }

                }
            }
        }

       
if (root ==   null ) {
            log.error(
" the root node is not be defined " );
        }
    }

    protected boolean isRootNode(TreeNode node ) {
       
return  StringUtils.isBlank(node.getParentId() ) ;
    }

    public TreeNode getRootNode() {
       
return root;
    }

   
public TreeNode getTreeNode(String nodeId) {
       
return (TreeNode) treeNodeMaps.get(nodeId);
    }

   
public   void addTreeNode(TreeNode node) {
       
synchronized ( this ) {
            treeNodeMaps.put(node.getNodeId(), node);

            String parentId
= node.getParentId();
           
if (StringUtils.isNotBlank(parentId)) {
                TreeNode parent
= getTreeNode(parentId);
               
if (parent !=   null ) {
                    parent.addChild(node);
                    node.setParent(parent);
                }
else {
                    log.error(
" parent cannot be found: "   + node.getParentId());
                }
            }
else {
               
if (root ==   null ) {
                    root
= node;
                }
else {
                    log.error(
" find more then one root node. ignore. " );
                }
            }
        }
    }

   
public   void deleteTreeNode(String nodeId) {
       
synchronized ( this ) {
            TreeNode node
= getTreeNode(nodeId);
           
if (node ==   null )
               
throw   new IllegalArgumentException(nodeId +   " cannot be found. " );

           
if (node.getParent() ==   null ) {
                root
=   null ;
                treeNodeMaps.clear();
                log.warn(
" the root node has been removed. " );
            }
else {
                node.getParent().getChildren().remove(node);

                treeNodeMaps.remove(nodeId);
                List children
= node.getAllChildren();
               
for ( int i =   0 ; i < children.size(); i ++ ) {
                    TreeNode n
= (TreeNode) children.get(i);
                    treeNodeMaps.remove(n.getNodeId());
                }
            }
        }
    }

   
/**
     * <pre>
     * Usage: Office -&gt;
     *
     * public TreeNode transform(Object info) {
     *     OfficeInfo office_info = (OfficeInfo) info;
     *     TreeNode node = new TreeNode();
     *     node.setNodeId(office_info.getOfficeId());
     *     node.setParentId(office_info.getParentId());
     *     node.setBindData(office_info);
     *     return node;
     * }
     * </pre>
    
*/
   
protected   abstract TreeNode transform(Object info);
}

TreeNode.java

package  com.humpic.helper .tree;

import java.util.List;
import java.util.Vector;

import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ObjectUtils;

public   class TreeNode {

   
private Tree tree;
   
private TreeNode parent;
   
private List children =   new Vector();
   
private List childrenGroup =   new Vector();
   
private String nodeId;
   
private String parentId;
   
private Object bindData;

   
public String getNodeId() {
       
return nodeId;
    }

   
public   void setNodeId(String nodeId) {
       
this .nodeId = nodeId;
    }

   
public String getParentId() {
       
return parentId;
    }

   
public   void setParentId(String parentId) {
       
this .parentId = parentId;
    }

   
public Object getBindData() {
       
return bindData;
    }

   
public   void setBindData(Object bindData) {
       
this .bindData = bindData;
    }

   
public Tree getTree() {
       
return tree;
    }

   
public   void setTree(Tree tree) {
       
this .tree = tree;
    }

   
public   void setParent(TreeNode parent) {
       
this .parent = parent;
    }

   
public TreeNode getParent() {
       
return   this .parent;
    }

   
public List getChildren() {
       
return   this .children;
    }

   
public   void addChild(TreeNode node) {
        children.add(node);
    }

   
/**
     * get all children, and chilren's children
    
*/
   
public List getAllChildren() {
       
if ( this .childrenGroup.isEmpty()) {
           
synchronized ( this .tree) {
               
for ( int i =   0 ; i <   this .children.size(); i ++ ) {
                    TreeNode node
= (TreeNode) this .children.get(i);
                   
this .childrenGroup.add(node);
                   
this .childrenGroup.addAll(node.getAllChildren());
                }
            }
        }
       
return   this .childrenGroup;
    }

   
/**
     * get all children, and chilren's children
    
*/
  
  public   List getAllChildren(Predicate predicate) {
        List groups
=   new Vector();
        fillAllChildren(groups, predicate);
       
return groups;
    }

   
private   void fillAllChildren(List groups, Predicate predicate) {
       
for ( int i =   0 ; i <   this .children.size(); i ++ ) {
            TreeNode node
= (TreeNode) this .children.get(i);
           
if (predicate.evaluate(node)) {
                groups.add(node);
                node.fillAllChildren(groups, predicate);
            }
        }
    }

    /**
     * get all parents, and parent's parent
    */

   
public List getParents() {
         List results =
new Vector();
        TreeNode parent =
this . getParent();
       
while (parent != null ) {
            results.add(parent);
            parent = parent.getParent();
        }
       
return results;
    }

   
/**
     * A.isMyParent(B) == B is A' parent ? <br>
     * root.isMyParent(null) == true; <br>
     * root.isMyParent(*) == false <br>
     * *.isMyParent(null) == false
    
*/
   
public   boolean isMyParent(String nodeId) {
        TreeNode target
= tree.getTreeNode(nodeId);
        TreeNode parent
=   this .getParent();
       
if (parent ==   null ) {
           
return target ==   null ;
        }
else {
           
return parent.equals(target);
        }
    }

   
/**
     * A.isMyAncestor(B) == B is A' ancestor ? <br>
     * *.isMyAncestor(null) == true;
    
*/
   
public   boolean isMyAncestor(String nodeId) {
        TreeNode target
= tree.getTreeNode(nodeId);
       
if (target ==   null )
           
return   true ;

       
return target.getAllChildren().contains( this );
    }

   
/**
     * A.isMyBrother(B) == B is A' brother ? <br>
     * *.isMyBrother(null) == false
    
*/
   
public   boolean isMyBrother(String nodeId) {
        TreeNode target
= tree.getTreeNode(nodeId);
       
if (target ==   null )
           
return   false ;

        TreeNode p1
=   this .getParent();
        TreeNode p2
= target.getParent();
       
return ObjectUtils.equals(p1, p2);
    }

}

然后建立业务 Tree

CatalogTree.java

package com.humpic.helper.tree;

import java.util.List;
import org.apache.commons.collections.Predicate;

public   class CatalogTree extends Tree {
   
private   static CatalogTree instance =   null ;

   
private CatalogTree() {}
   
   
public   static synchronized CatalogTree getInstance() {
       
if (instance ==   null ) {
            instance =   new CatalogTree();
            instance.reloadCatalogs();
        }
       
return instance;
    }

   
protected TreeNode transform(Object info) {
        Catalog catalog
= (Catalog) info;
        TreeNode node
=   new TreeNode();
        node.setNodeId(catalog.getCatalogId());
        node.setParentId(catalog.getParentId());
        node.setBindData(catalog);
       
return node;
    }

   
public   void reloadCatalogs() {
        List nodes
= CatalogDAO.getInstance().findAll();
       
super .reload(nodes);
    }

   
public Catalog getCatalogNode(String catalogId) {
        TreeNode node
=   super .getTreeNode(catalogId);
       
return node ==   null   ?   null : (Catalog) node.getBindData();
    }
}

最后,我们只要使用以下的语句就可以了:

1. CatalogTree.getInstance().getTreeNode(...)
2. CatalogTree.getInstance().getCatalogNode(...)
3. CatalogTree.getInstance().getRootNode()

然后通过 TreeNode,就可以得到 parent, parents 和 children, allChildren

分享到:
评论

相关推荐

    MF00716-Java企业级开发平台源码.zip

    Java企业级开发平台源码 权限管理框架源码 开发语言 : JAVA 数据库 : MySQL ...富文本:KindEcitor、数据表格:jqGrid、树结构控件:jQuery zTree 弹出层:Layer、日期控件: LayDate、图表控件:echarts

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     19.1.4 由Java应用本身提供数据库连接  19.2 配置事务类型  19.3 把SessionFactory与JNDI绑定  19.4 配置日志  19.5 使用XML格式的配置文件  19.6 小结  19.7 思考题 第20章 声明数据库事务  20.1 数据库...

    java开源包10

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    数据库优化设计方案.doc

    为此,数据库平台一般对表空间设计提 出有相应的优化结构,如ORACLE公司的OFA(Optimal flexible Architecture),使用这种结构进行设计会大大简化物理设计中的数据管理。优化自由结 构,简单地讲就是在数据库中可以...

    Oracle自学(学习)材料 (共18章 偏理论一点)

    1 Oracle 结构组件 目标 1-2 基本结构概述 1-3 Oracle 服务器 1-4 Oracle 实例 1-5 建立连接和创建会话 1-6 Oracle 数据库 1-7 物理结构 1-8 内存结构 1-9 系统全局区(SGA) 1-10 共享池 1-12 库缓存 1-13 数据字典...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    micro-DB:自己动手写数据库-基于Java语言的简易关系型数据库

    涉及缓存,数据容量存储结构(B +树),锁,事务,优化器,重做/撤消日志等核心原理。 1.关系数据结构基本定义 添加数据库,表,行,细分等基础定义 2.数据持久化 每一个表存储成为一个物理磁盘文件,通过表数据变多...

    java开源包1

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    JAVA上百实例源码以及开源项目源代码

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    java开源包4

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包11

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包6

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包9

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包5

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包8

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包3

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    JAVA高并发高性能高可用高扩展架构视频教程

    打造高效代码结构(java性能优化) 新版本通俗易懂_观察者模式递进时讲解 ibatis连接数据库 高并发之单(多)生产者消费者线程 高并发复用数据库链接技术详解之数据库连接池 类加载器的高级特性(自定义类加器实现加密...

    软件设计师重点考点

    4.2结构化程序设计、面向对象程序设计、可视化程序设计 248 4.3系统测试的目的、类型,系统测试方法 248 4.4系统转换基础知识 249 5.系统运行和维护知识 249 5.1系统运行管理基础知识 249 5.2系统维护基础知识 250 ...

    java开源包2

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

    java开源包7

    SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的...

Global site tag (gtag.js) - Google Analytics