`
leaves615
  • 浏览: 3639 次
  • 性别: 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

分享到:
评论

相关推荐

    advanced-java-master.zip

    - 常见数据结构:数组、链表、栈、队列、树、图等。 - 常见算法:排序(冒泡、选择、插入、快速等)、查找、递归、动态规划等。 9. **分布式** - 分布式ID生成:如Snowflake算法。 - 分布式缓存:Redis的使用和...

    common_加入缓存AOP,树结构路径参数填充_.zip

    通过阅读和学习这个示例,我们可以了解到如何在实际项目中应用缓存AOP以及如何处理树结构路径参数。这种实践对于提升我们的编程技巧和解决问题的能力非常有帮助。 总结来说,"common_加入缓存AOP,树结构路径参数...

    数据结构与算法-java

    以下是基于标题“数据结构与算法-java”及描述中提到的“数据结构与算法分析_Java语言描述高清版(第2版)1.pdf”所涵盖的一些关键知识点: 1. **数据结构**: - **数组**:最基础的数据结构,存储固定大小的同类型...

    java读取纯真IP地址数据库

    在Java编程环境中,读取纯真IP地址数据库是一项常见的任务,尤其对于需要进行IP定位或者网络管理的应用来说。纯真IP数据库(通常称为QQWRY或IPSeeker)是一个包含了全球IP地址及其对应地理位置信息的数据库,它由一...

    在java中 遍历mysql中的树形结构

    在Java中遍历MySQL数据库中的树形结构是一个复杂但重要的任务,涉及数据库设计、递归算法以及性能优化等多个方面。通过深入理解树形结构的特点,并采用合适的遍历算法和优化策略,可以有效地管理和操作复杂的层级...

    内存数据库代码有详细设计说明(java版)

    Java中的synchronized关键字和java.util.concurrent包提供了线程安全的数据结构和并发工具,可以用来实现乐观锁、悲观锁或读写锁等并发控制策略。此外,内存数据库必须支持ACID(原子性、一致性、隔离性和持久性)...

    java面试——上海-拼多多-Java高级.zip

    在Java高级面试中,拼多多作为一家知名的电商平台,对求职者的技能要求往往较高。这份压缩包文件"java面试——上海-拼多多-Java高级.zip"包含了针对Java高级开发人员的面试问题和解答,帮助应聘者准备面试。以下是...

    毕业论文设计-IT计算机-JAVA泡泡堂网络游戏的设计与实现(源代码+论文).zip

    7. **数据结构与算法**:游戏中的碰撞检测、路径规划等需要高效的数据结构(如数组、链表、树等)和算法支持,例如A*寻路算法、四叉树碰撞检测等。 8. **安全性**:网络安全是必须考虑的问题,如防止作弊、保护用户...

    阿里规约-Java开发手册 v-1.7.0(嵩山版).rar

    - 对于频繁访问的数据结构,考虑使用哈希表或红黑树等高效数据结构。 9. **测试规约**: - 每个类或关键功能模块应编写相应的单元测试。 - 测试用例需覆盖正常情况、边界情况和异常情况。 - 测试代码应与生产...

    java 数据库实现(设计模拟DBMS)

    - 索引可以极大地提升查询性能,Java中的数据库实现可能需要支持B树、哈希索引等数据结构。 - 查询优化是选择最佳执行计划的过程,包括考虑表的连接顺序、是否使用索引等。 4. **事务处理**: - 事务是数据库...

    SR-tree-java.zip_java tree_sr tree_tree

    在SR树中,基数树结构用于处理多维数据的分层索引。 4. **SRTree.java和AbstractNode.java**:这两个文件很可能是SR树的核心实现类。`SRTree.java`可能包含了SR树的构造、插入、删除和查询等操作,而`AbstractNode....

    非常实用的树形菜单,有数据库表

    在给定的标题“非常实用的树形菜单,有数据库表”和描述“java实现的非常实用的树形菜单,有数据库表”中,我们可以深入探讨几个关键知识点: 1. **树形菜单**:树形菜单是一种层次结构的展示方式,它通过节点和边...

    mysql面试题-mysql经典面试题目-数据库的基本概念-SQL语法-事务处理-索引优化-性能调优-mysql-面试题目

    索引是一种特殊的数据结构,它提高了对数据库表中数据的查找速度。通过在列上创建索引,可以加快查询性能,因为数据库系统不再需要全表扫描,而是直接定位到所需的数据行。然而,索引也会占用额外的存储空间,并可能...

    java面试——广州-唯品会-Java大数据开发工程师.zip

    在Java大数据开发工程师的面试中,考察的知识点广泛且深入,涵盖Java编程基础、大数据处理框架、分布式系统、数据库管理、算法与数据结构等多个方面。以下是对这些关键领域的详细解读: 1. **Java编程基础**: - *...

    butte-java-note-编程文档

    在“butte-java-note-编程文档”中,我们可以探索一系列丰富的IT知识点,涵盖了从基础到高级的Java编程、软件设计、系统架构以及大数据处理等多个领域。以下是对这些知识点的详细阐述: 1. **JVM(Java虚拟机)**:...

    java面试——深圳-中国平安-Java中级.zip

    在Java面试过程中,尤其是针对中级开发者的职位,面试官通常会关注候选人的基础知识、编程能力、框架理解以及项目经验。深圳作为中国的科技中心之一,中国平安作为一家知名的金融技术公司,其对Java开发者的要求自然...

    一次集合遍历实现树形结构 - server

    在IT领域,构建树形结构的数据模型是一种...总之,一次集合遍历实现树形结构是Java和Spring Boot开发中处理层级数据的一种有效方法,它既简洁又高效。理解并掌握这种技巧,对提升后端服务的性能和可维护性大有裨益。

    butte-java-note编程文档

    此外,它还涵盖了软件设计模式、数据结构与算法、系统架构设计等高级主题,以及在实际开发中常用的Spring框架、中间件技术、大数据处理、数据库管理、Linux操作系统知识和数据服务相关内容。 【描述】的关键词点...

    北京-百度-Java中级面试真题.zip

    因此,对于Java语言的理解,例如面向对象设计原则、多线程处理、集合框架的深入理解以及异常处理机制,这些都是面试中的常见话题。在百度的面试中,面试官可能会询问关于JVM(Java虚拟机)的工作原理,如内存模型、...

    Rtree-java

    在Java中,Rtree-java库提供了一种实现R树的方法,使得开发者能够方便地在应用程序中管理、存储和查询多维数据。R树的主要优点在于它可以有效地处理高维数据集,降低因维度灾难( Curse of Dimensionality )导致的...

Global site tag (gtag.js) - Google Analytics