Hibernate 树状映射

目录:

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

[一]、概述

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

[二]、环境

  • hibernate 4.1.2
  • java 1.6
  • mysql 5.1

[三]、代码示例

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

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

TreeNode.Java

[java]  view plain  copy
  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 Michael Sun 
  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 children = new LinkedHashSet();  
  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 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 children) {  
  77.         this.children = children;  
  78.     }  
  79. }  

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

hibernate.cfg.xml

[java]  view plain  copy
  1. '1.0' encoding='UTF-8'?>  
  2.           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  3.           "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
  4.   
  5.   
  6.   
  7.       
  8.   
  9.         "dialect">org.hibernate.dialect.MySQLDialect  
  10.         "connection.driver_class">com.mysql.jdbc.Driver  
  11.         "connection.url">jdbc:mysql://localhost:3306/michaeldemo  
  12.         "connection.username">root  
  13.         "connection.password">  
  14.   
  15.         "show_sql">true  
  16.         "format_sql">true  
  17.   
  18.         "current_session_context_class">thread  
  19.         "hbm2ddl.auto">update  
  20.   
  21.         class="com.micmiu.hibernate.anno.entity.TreeNode" />  
  22.       
  23.   
  24.   

第三步:创建测试文件:

HibernateAnnoTreeTest.java

[java]  view plain  copy
  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 Michael Sun 
  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.class1);  
  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.class1);  
  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.class6);  
  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.class6);  
  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

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

 --------------------------------------------------------------

[java]  view plain  copy
  1. public class NodeManage {  
  2.       
  3.     private static NodeManage nodeManage= new NodeManage();  
  4.       
  5.     private NodeManage(){}//因为要使用单例,所以将其构造方法私有化  
  6.       
  7.     //向外提供一个接口  
  8.     public static NodeManage getInstanse(){  
  9.         return nodeManage;  
  10.     }  
  11.   
  12.     /** 
  13.      * 创建树 
  14.      * @param filePath 需要创建树目录的根目录 
  15.      */  
  16.     public void createNode(String dir) {  
  17.         Session session = null;  
  18.           
  19.         try {  
  20.             session = HibernateUtils.getSession();  
  21.             session.beginTransaction();  
  22.               
  23.             File root = new File(dir);  
  24.             //因为第一个节点无父节点,因为是null  
  25.             this.saveNode(root, session, null0);  
  26.               
  27.             session.getTransaction().commit();  
  28.         } catch (HibernateException e) {  
  29.             e.printStackTrace();  
  30.             session.getTransaction().rollback();  
  31.         } finally {  
  32.             HibernateUtils.closeSession(session);  
  33.         }  
  34.     }  
  35.   
  36.     /** 
  37.      * 保存节点对象至数据库 
  38.      * @param file 节点所对应的文件 
  39.      * @param session session 
  40.      * @param parent 父节点 
  41.      * @param level 级别 
  42.      */  
  43.     public void saveNode(File file, Session session, Node parent, int level) {  
  44.           
  45.         if (file == null || !file.exists()){  
  46.             return;  
  47.         }  
  48.           
  49.         //如果是文件则返回true,则表示是叶子节点,否则为目录,非叶子节点  
  50.         boolean isLeaf = file.isFile();  
  51.           
  52.         Node node = new Node();  
  53.         node.setName(file.getName());  
  54.         node.setLeaf(isLeaf);  
  55.         node.setLevel(level);  
  56.         node.setParent(parent);  
  57.           
  58.         session.save(node);  
  59.           
  60.         //进行循环迭代子目录  
  61.         File[] subFiles = file.listFiles();  
  62.         if (subFiles != null && subFiles.length > 0){  
  63.             for (int i = 0; i < subFiles.length ; i++){  
  64.                 this.saveNode(subFiles[i], session, node, level + 1);  
  65.             }  
  66.         }  
  67.     }  
  68.   
  69.     /** 
  70.      * 输出树结构 
  71.      * @param id 
  72.      */  
  73.     public void printNodeById(int id) {  
  74.   
  75.         Session session = null;  
  76.           
  77.         try {  
  78.             session = HibernateUtils.getSession();  
  79.             session.beginTransaction();  
  80.               
  81.             Node node = (Node)session.get(Node.class1);  
  82.               
  83.             printNode(node);  
  84.               
  85.             session.getTransaction().commit();  
  86.         } catch (HibernateException e) {  
  87.             e.printStackTrace();  
  88.             session.getTransaction().rollback();  
  89.         } finally {  
  90.             HibernateUtils.closeSession(session);  
  91.         }         
  92.     }  
  93.   
  94.       
  95.     private void printNode(Node node) {  
  96.           
  97.         if (node == null){  
  98.             return;  
  99.         }  
  100.           
  101.         int level = node.getLevel();  
  102.           
  103.         if (level > 0){  
  104.             for (int i = 0; i < level; i++){  
  105.                 System.out.print("  |");  
  106.             }  
  107.             System.out.print("--");               
  108.         }  
  109.         System.out.println(node.getName() + (node.isLeaf() ? "" : "[" + node.getChildren().size() + "]"));  
  110.           
  111.         Set children = node.getChildren();  
  112.         for (Iterator iter = children.iterator(); iter.hasNext(); ){  
  113.             Node child = (Node)iter.next();  
  114.             printNode(child);  
  115.         }  
  116.     }  
  117. }  

你可能感兴趣的:(Hibernate)