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

目录:

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

[一]、概述

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

[二]、环境

  • hibernate 4.1.2
  • java 1.6
  • mysql 5.1

[三]、代码示例

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

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

TreeNode.java

1package com.micmiu.hibernate.anno.entity;
2 
3import java.util.LinkedHashSet;
4import java.util.Set;
5 
6import javax.persistence.CascadeType;
7import javax.persistence.Column;
8import javax.persistence.Entity;
9import javax.persistence.FetchType;
10import javax.persistence.GeneratedValue;
11import javax.persistence.Id;
12import javax.persistence.JoinColumn;
13import javax.persistence.ManyToOne;
14import javax.persistence.OneToMany;
15import 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")
24public 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

1package com.micmiu.hibernate;
2 
3import org.hibernate.Session;
4import org.hibernate.SessionFactory;
5import org.hibernate.cfg.Configuration;
6import org.hibernate.service.ServiceRegistry;
7import org.hibernate.service.ServiceRegistryBuilder;
8import org.junit.AfterClass;
9import org.junit.BeforeClass;
10import org.junit.Test;
11 
12import com.micmiu.hibernate.anno.entity.TreeNode;
13 
14/**
15 * 测试
16 *
17 * @author <a href="http://www.micmiu.com">Michael Sun</a>
18 */
19public 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
2log4j.rootLogger=info, Console
3 
4#Console
5log4j.appender.Console=org.apache.log4j.ConsoleAppender
6log4j.appender.Console.layout=org.apache.log4j.PatternLayout
7log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
8 
9log4j.logger.org.hibernate.tool.hbm2ddl=debug
10log4j.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 <========

数据库中查询记录如下:

本文介绍到此结束

转载于:https://www.cnblogs.com/gzwlj/p/3462089.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值