• Hibernate注解实现单表递归树形结构


    目录:

    1. 概述
    2. 环境
    3. 代码示例
    4. 测试结果

    [一]、概述

    在系统中,经常会用到无限级递归的树形结构,比如菜单、组织机构管理、多级分类等等,一般是在同一个表中定义父子关系实现这种树形结构,本文主要讲述如何运用hibernate全注解的方式实现这个功能。

    [二]、环境

    • hibernate 4.1.2
    • java 1.6
    • mysql 5.1

    [三]、代码示例

    第一步:创建Entity类,并添加注解实现关联关系

    ps: 主要是利用@ManyToOne 和 @OneToMany 配置在同一个Entity类中实现树形递归的结构

    TreeNode.java

    1 package com.micmiu.hibernate.anno.entity;
    2  
    3 import java.util.LinkedHashSet;
    4 import java.util.Set;
    5  
    6 import javax.persistence.CascadeType;
    7 import javax.persistence.Column;
    8 import javax.persistence.Entity;
    9 import javax.persistence.FetchType;
    10 import javax.persistence.GeneratedValue;
    11 import javax.persistence.Id;
    12 import javax.persistence.JoinColumn;
    13 import javax.persistence.ManyToOne;
    14 import javax.persistence.OneToMany;
    15 import javax.persistence.Table;
    16  
    17 /**
    18  * 树形结构示例
    19  *
    20  * @author <a href="http://www.micmiu.com">Michael Sun</a>
    21  */
    22 @Entity
    23 @Table(name = "DEMO_T_TREE_NODE")
    24 public class TreeNode {
    25  
    26     public TreeNode() {
    27     }
    28  
    29     public TreeNode(String name) {
    30         this.name = name;
    31     }
    32  
    33     private int id;
    34  
    35     private String name;
    36     // 父节点
    37     private TreeNode parent;
    38     // 子节点
    39     private Set<TreeNode> children = new LinkedHashSet<TreeNode>();
    40  
    41     @Id
    42     @Column(name = "ID")
    43     @GeneratedValue
    44     public int getId() {
    45         return id;
    46     }
    47  
    48     @Column(name = "NAME", length = 20)
    49     public String getName() {
    50         return name;
    51     }
    52  
    53     @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    54     @JoinColumn(name = "PARENT_ID")
    55     public TreeNode getParent() {
    56         return parent;
    57     }
    58  
    59     @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.EAGER)
    60     public Set<TreeNode> getChildren() {
    61         return children;
    62     }
    63  
    64     public void setId(int id) {
    65         this.id = id;
    66     }
    67  
    68     public void setName(String name) {
    69         this.name = name;
    70     }
    71  
    72     public void setParent(TreeNode parent) {
    73         this.parent = parent;
    74     }
    75  
    76     public void setChildren(Set<TreeNode> children) {
    77         this.children = children;
    78     }
    79 }

    第二步:创建hibernate默认配置文件:

    hibernate.cfg.xml

    1 <?xml version='1.0' encoding='UTF-8'?>
    2 <!DOCTYPE hibernate-configuration PUBLIC
    3           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    5  
    6 <hibernate-configuration>
    7  
    8     <session-factory>
    9  
    10         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    11         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    12         <property name="connection.url">jdbc:mysql://localhost:3306/michaeldemo</property>
    13         <property name="connection.username">root</property>
    14         <property name="connection.password"></property>
    15  
    16         <property name="show_sql">true</property>
    17         <property name="format_sql">true</property>
    18  
    19         <property name="current_session_context_class">thread</property>
    20         <property name="hbm2ddl.auto">update</property>
    21  
    22         <mapping class="com.micmiu.hibernate.anno.entity.TreeNode" />
    23     </session-factory>
    24  
    25 </hibernate-configuration>

    第三步:创建测试文件:

    HibernateAnnoTreeTest.java

    1 package com.micmiu.hibernate;
    2  
    3 import org.hibernate.Session;
    4 import org.hibernate.SessionFactory;
    5 import org.hibernate.cfg.Configuration;
    6 import org.hibernate.service.ServiceRegistry;
    7 import org.hibernate.service.ServiceRegistryBuilder;
    8 import org.junit.AfterClass;
    9 import org.junit.BeforeClass;
    10 import org.junit.Test;
    11  
    12 import com.micmiu.hibernate.anno.entity.TreeNode;
    13  
    14 /**
    15  * 测试
    16  *
    17  * @author <a href="http://www.micmiu.com">Michael Sun</a>
    18  */
    19 public class HibernateAnnoTreeTest {
    20  
    21     private static SessionFactory sessionFactory;
    22  
    23     @BeforeClass
    24     public static void beforeClass() {
    25         Configuration configuration = new Configuration().configure();
    26         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
    27                 .applySettings(configuration.getProperties())
    28                 .buildServiceRegistry();
    29         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    30  
    31     }
    32  
    33     @AfterClass
    34     public static void afterClass() {
    35         sessionFactory.close();
    36     }
    37  
    38     @Test
    39     public void testTreeCRUD() {
    40         // 先运行添加测试
    41         // testSave();
    42  
    43         // 读取测试
    44         // testRead();
    45  
    46         // 更新测试
    47         testUpdate();
    48  
    49         // 删除测试
    50         // testDelete();
    51     }
    52  
    53     public void testSave() {
    54         System.out.println("========>测试添加 start <========");
    55         Session session = sessionFactory.openSession();
    56  
    57         session.beginTransaction();
    58         TreeNode rootNode = initData();
    59         session.save(rootNode);
    60         session.getTransaction().commit();
    61         session.close();
    62         System.out.println("========>测试添加 end <========");
    63         // 读取添加的数据
    64         testRead();
    65     }
    66  
    67     public void testRead() {
    68         System.out.println("========>读取 start <========");
    69         Session session = sessionFactory.openSession();
    70         session.beginTransaction();
    71         System.out.println("-----> get root node:");
    72         TreeNode rootNode = (TreeNode) session.get(TreeNode.class, 1);
    73  
    74         System.out.println("-----> 输出树形结构如下:");
    75         printNode(rootNode, 0);
    76  
    77         session.getTransaction().commit();
    78         session.close();
    79         System.out.println("========>读取 end <========");
    80     }
    81  
    82     public void testUpdate() {
    83         // 更新前读取信息
    84         testRead();
    85         System.out.println("========>测试更新 start <========");
    86         Session session = sessionFactory.openSession();
    87         session.beginTransaction();
    88  
    89         System.out.println("---> 更新节点属性");
    90         TreeNode rootNode = (TreeNode) session.get(TreeNode.class, 1);
    91         System.out.println("get root node:" + rootNode.getName()
    92                 + " child size:" + rootNode.getChildren().size());
    93         rootNode.setName(rootNode.getName() + "(我的blog)");
    94  
    95         TreeNode node_del = null;
    96         for (TreeNode node : rootNode.getChildren()) {
    97             if ("Hazel".equals(node.getName())) {
    98                 node_del = node;
    99             }
    100         }
    101         System.out.println("---> 删除节点(包含子节点)");
    102         System.out.println("delete node:" + node_del.getName() + " child size:"
    103                 + node_del.getChildren().size());
    104         node_del.setParent(null);
    105         rootNode.getChildren().remove(node_del);
    106         session.delete(node_del);
    107  
    108         System.out.println("---> 添加节点(包含子节点)");
    109         TreeNode node_add = new TreeNode("企业应用");
    110         node_add.setParent(rootNode);
    111         rootNode.getChildren().add(node_add);
    112  
    113         TreeNode node_add_0 = new TreeNode("SNMP");
    114         node_add_0.setParent(node_add);
    115         node_add.getChildren().add(node_add_0);
    116  
    117         TreeNode node_add_1 = new TreeNode("SSO");
    118         node_add_1.setParent(node_add);
    119         node_add.getChildren().add(node_add_1);
    120  
    121         session.update(rootNode);
    122  
    123         System.out.println("---> 节点下添加子节点");
    124         TreeNode node_update = (TreeNode) session.get(TreeNode.class, 6);
    125         TreeNode node_child_add = new TreeNode("go(新增)");
    126         System.out.println("append child node:" + node_child_add.getName()
    127                 + " to parent node: " + node_update.getName());
    128         node_child_add.setParent(node_update);
    129         node_update.getChildren().add(node_child_add);
    130  
    131         System.out.println("---> 节点下删除子节点");
    132  
    133         TreeNode node_child_del = node_update.getChildren().iterator().next();
    134         System.out.println("delete node child :" + node_child_del.getName()
    135                 + " from parent node: " + node_update.getName());
    136         node_update.getChildren().remove(node_child_del);
    137         node_child_del.setParent(null);
    138         session.delete(node_child_del);
    139  
    140         session.update(node_update);
    141  
    142         session.getTransaction().commit();
    143         session.close();
    144         System.out.println("========>测试更新 end <========");
    145         // 更新后读取信息
    146         testRead();
    147     }
    148  
    149     public void testDelete() {
    150         // 删除前读取信息
    151         testRead();
    152         System.out.println("========>测试删除 start <========");
    153         Session session = sessionFactory.openSession();
    154         session.beginTransaction();
    155         TreeNode node = (TreeNode) session.get(TreeNode.class, 6);
    156         System.out.println("node:" + node.getName() + " child size:"
    157                 + node.getChildren().size());
    158         TreeNode childNode = node.getChildren().iterator().next();
    159         childNode.setParent(null);
    160         node.getChildren().remove(childNode);
    161         session.delete(childNode);
    162         System.out.println("delete node:" + childNode.getName()
    163                 + " from parent:" + node.getName());
    164  
    165         session.update(node);
    166         session.getTransaction().commit();
    167         session.close();
    168         System.out.println("========>测试删除 end <========");
    169         // 删除后读取信息
    170         testRead();
    171  
    172     }
    173  
    174     /**
    175      * 模拟测试数据
    176      */
    177     private TreeNode initData() {
    178         TreeNode rootNode = new TreeNode("micmiu.com");
    179  
    180         // 一级
    181         TreeNode node0 = new TreeNode("Michael");
    182         node0.setParent(rootNode);
    183         rootNode.getChildren().add(node0);
    184  
    185         // 二级
    186         TreeNode node0_0 = new TreeNode("J2EE");
    187         node0_0.setParent(node0);
    188         node0.getChildren().add(node0_0);
    189         // 二级
    190         TreeNode node0_1 = new TreeNode("SOA");
    191         node0_1.setParent(node0);
    192         node0.getChildren().add(node0_1);
    193         // 二级
    194         TreeNode node0_2 = new TreeNode("NoSQL");
    195         node0_2.setParent(node0);
    196         node0.getChildren().add(node0_2);
    197  
    198         // 二级
    199         TreeNode node0_3 = new TreeNode("编程语言");
    200         node0_3.setParent(node0);
    201         node0.getChildren().add(node0_3);
    202  
    203         // 三级
    204         TreeNode node0_3_0 = new TreeNode("Java");
    205         node0_3_0.setParent(node0_3);
    206         node0_3.getChildren().add(node0_3_0);
    207  
    208         TreeNode node0_3_1 = new TreeNode("Groovy");
    209         node0_3_1.setParent(node0_3);
    210         node0_3.getChildren().add(node0_3_1);
    211  
    212         TreeNode node0_3_2 = new TreeNode("javascript");
    213         node0_3_2.setParent(node0_3);
    214         node0_3.getChildren().add(node0_3_2);
    215  
    216         // 一级
    217         TreeNode node1 = new TreeNode("Hazel");
    218         node1.setParent(rootNode);
    219         rootNode.getChildren().add(node1);
    220         // 二级
    221         TreeNode node1_0 = new TreeNode("life");
    222         node1_0.setParent(node1);
    223         node1.getChildren().add(node1_0);
    224         // 二级
    225         TreeNode node1_1 = new TreeNode("美食");
    226         node1_1.setParent(node1);
    227         node1.getChildren().add(node1_1);
    228         // 二级
    229         TreeNode node1_2 = new TreeNode("旅游");
    230         node1_2.setParent(node1);
    231         node1.getChildren().add(node1_2);
    232  
    233         return rootNode;
    234     }
    235  
    236     private void printNode(TreeNode node, int level) {
    237         String preStr = "";
    238         for (int i = 0; i < level; i++) {
    239             preStr += "|----";
    240         }
    241         System.out.println(preStr + node.getName());
    242         for (TreeNode children : node.getChildren()) {
    243             printNode(children, level + 1);
    244         }
    245     }
    246  
    247 }

    第四步:创建日志输出配置文件:

    log4j.properties

    1 # Output pattern : date [thread] priority category - message
    2 log4j.rootLogger=info, Console
    3  
    4 #Console
    5 log4j.appender.Console=org.apache.log4j.ConsoleAppender
    6 log4j.appender.Console.layout=org.apache.log4j.PatternLayout
    7 log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
    8  
    9 log4j.logger.org.hibernate.tool.hbm2ddl=debug
    10 log4j.logger.org.hibernate.test=info

    [四]、测试结果

    测试添加方法,输出日志如下:

    ========>测试添加 start <========
    ========>测试添加 end <========
    ========>读取 start <========
    -----> get root node:
    -----> 输出树形结构如下:
    micmiu.com
    |----Michael
    |----|----J2EE
    |----|----SOA
    |----|----NoSQL
    |----|----编程语言
    |----|----|----Java
    |----|----|----Groovy
    |----|----|----javascript
    |----Hazel
    |----|----life
    |----|----美食
    |----|----旅游
    ========>读取 end <========

    数据库中查询记录如下:

    再运行测试程序中的更新方法,输出日志如下:

    ========>读取 start <========
    -----> get root node:
    -----> 输出树形结构如下:
    micmiu.com
    |----Michael
    |----|----J2EE
    |----|----SOA
    |----|----NoSQL
    |----|----编程语言
    |----|----|----Java
    |----|----|----Groovy
    |----|----|----javascript
    |----Hazel
    |----|----life
    |----|----美食
    |----|----旅游
    ========>读取 end <========
    ========>测试更新 start <========
    ---> 更新节点属性
    get root node:micmiu.com child size:2
    ---> 删除节点(包含子节点)
    delete node:Hazel child size:3
    ---> 添加节点(包含子节点)
    ---> 节点下添加子节点
    append child node:go(新增) to parent node: 编程语言
    ---> 节点下删除子节点
    delete node child :Java from parent node: 编程语言
    ========>测试更新 end <========
    ========>读取 start <========
    -----> get root node:
    -----> 输出树形结构如下:
    micmiu.com(我的blog)
    |----Michael
    |----|----J2EE
    |----|----SOA
    |----|----NoSQL
    |----|----编程语言
    |----|----|----Groovy
    |----|----|----javascript
    |----|----|----go(新增)
    |----企业应用
    |----|----SNMP
    |----|----SSO
    ========>读取 end <========

    数据库中查询记录如下:

    本文介绍到此结束

  • 相关阅读:
    uva 532
    uva 10557
    uva 705
    uva 784
    uva 657
    uva 572
    uva 10562
    usa物价统计
    2019/6/30,道歉书
    名词收集
  • 原文地址:https://www.cnblogs.com/gzwlj/p/3462089.html
Copyright © 2020-2023  润新知