Hibernate基于配置文件(十一)多对一双向关联树形结构的映射

本文介绍如何利用Hibernate框架实现树形结构的高效管理,通过优化查询方式减少数据库操作次数,提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用Hibernate建立树形结构

 

递归查询子节点,会发出N多次select查询

可以在Node中定义一个字段,额外记录其与parent的id间的关系,如1|3|6|12

然后使用like进行模糊查询,只需要查询1次即可找出所有的child。

虽然模糊查询慢,但只发出1条语句,所以效率可能比发出N多次递归查询快!

 

实体类

package org.leadfar.hibernate.model;

import java.util.Set;

public class Node {
	private int id;
	private String name;
	private Node parent;
	private Set<Node> children;//一的一端使用集合存储对方引用
	
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Node getParent() {
		return parent;
	}
	public void setParent(Node parent) {
		this.parent = parent;
	}
	public Set<Node> getChildren() {
		return children;
	}
	public void setChildren(Set<Node> children) {
		this.children = children;
	}
	
}

 

 

 映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping 
	package="org.hibernate.auction">
	<class name="org.leadfar.hibernate.model.Node" table="t_node" >
		<!-- id为数据库标识,作为主键 -->
		<id name="id">
			<generator class="native"/>
		</id>
		
		<property name="name"/>
		<many-to-one name="parent" column="pid"> </many-to-one>
		<set name="children" lazy="extra" inverse="true">
			<key column="pid"></key>
			<one-to-many class="org.leadfar.hibernate.model.Node"></one-to-many>
		</set>
	</class>
	
</hibernate-mapping>

 

 

测试

package org.leadfar.hibernate.model;
import java.io.File;
import java.util.Iterator;
import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Test_tree extends TestCase {
	/**
	 * 建立一个文件目录树。可以根据某个节点查找其父节点,也可以查找其子节点
	 * 查找父节点--many-to-one
	 * 查找子节点--one-to-many
	 * 
	 * 关联关系---parent字段,可以看做是外键
	 * 从多的一端即孩子端建立关联关系
	 */
	public void tree_save() {
		Configuration cfg = new Configuration().configure();
		
		
		SessionFactory sfactory = cfg.buildSessionFactory();
		
		
		Session session = sfactory.openSession();
		
		try {
			
			session.beginTransaction();
			
			save(session,new File("F:\\oracle"),null);
			

			session.getTransaction().commit();
			
		} catch(Exception e) {
			e.printStackTrace();
			
			session.getTransaction().rollback();
		} finally {
			
			session.close();
		}
		
	}
	public void tree_findParent() {
		Configuration cfg = new Configuration().configure();
		
		
		SessionFactory sfactory = cfg.buildSessionFactory();
		
		
		Session session = sfactory.openSession();
		
		try {
			
			session.beginTransaction();
			

			
			Node node = (Node)session.load(Node.class, 2034);
			find_parent(node);
			
			session.getTransaction().commit();
			
		} catch(Exception e) {
			e.printStackTrace();
			
			session.getTransaction().rollback();
		} finally {
			
			session.close();
		}
		
	}
	public void tree_findChild() {
		Configuration cfg = new Configuration().configure();

		SessionFactory sfactory = cfg.buildSessionFactory();
		
		Session session = sfactory.openSession();
		
		try {
			
			session.beginTransaction();

			Node node = (Node)session.load(Node.class, 22);
			find_child(node,0);
			
			session.getTransaction().commit();
			
		} catch(Exception e) {
			e.printStackTrace();
			
			session.getTransaction().rollback();
		} finally {
			
			session.close();
		}
		
	}
	
	//保存一个文件目录树到数据库---parent记录父子关系
	private void save(Session session,File file,Node parent) {
		Node node = new Node();
		node.setName(file.getName());
		node.setParent(parent);
		
		session.save(node);
		
		if(file.exists()) {
			File[] f = file.listFiles();
			if(f!=null && f.length>0) {
				for(File sub : f) {
					if(sub.isDirectory())
						save(session,sub,node);
				}
			}
		}
	}
	
	//查找给定节点的父节点
	private void find_parent(Node node) {
		System.out.print(node.getName());
		Node parent = node.getParent();
		if(parent!=null) {
			System.out.print("-->");
			find_parent(parent);
		}
	}
	
	//给定节点查找其子节点
	private void find_child(Node node,int level) {
		for(int i=0;i<level;i++) {
			System.out.print("\t");
		}
		System.out.println(node.getName());
		Set<Node> childs = node.getChildren();
		if(childs.size()!=0) {
			for(Node n : childs){
				find_child(n,level+1);
			}
		}
	}
}

 

嗯,我现在要设计一个通用的用户管理模块, 需要实现用户管理、权限管理和角色分工,可 能还要用GUI或者Web应用开发,不过用户这 里没说具体用哪个,先按通用的来考虑。然后 要尽量使用设计模式,还要考虑大规模应用, 比如角色可能有几十种,数据存储要用文件或 数据库数据库要考虑迁移问题。最后还要写 设计报告,包括思路、类图、设计模式、Java 代码。好,先从头开始思考。 首先,用户管理模块通常包括用户、角色、权 限这几个核心部分。用户属于某个或多个角 色,角色拥有多个权限。权限可能分为不同的 类型,比如模块权限、操作权限等。在大规模 应用中,角色可能有几十种,所以需要设计灵 活的结构,避免硬编码角色和权限的关系。 接下来要考虑数据存储。用户提到数据库要考 虑迁移问题,所以可能需要使用ORM框架,比 如Hibernate或者MyBatis,这样换数据库时改 动较小。不过如果只是简单的话,也可以使用 JDBC,但这样迁移起来可能麻烦。或者用 Spring Data JPA,这样底层数据库可以切 换,比如H2、MySQL等,方便迁移。另外 数据存储部分应该抽象出来,方便切换不同的 存储方式,比如文件或数据库。这里可能需要 用抽象工厂模式或者策略模式来选择存储方 式。 然后是设计模式的应用。可能的模式包括: 1.策略模式:用于不同的存储策略,比如数据 库存储和文件存储。 2.工厂模式:创建用户、角色、权限等对象。 3.单例模式;比如配置类或者数据库连接池。 4.观察者模式:比如当用户权限变更时通知其 他模块。 5.装饰者模式:动态添加权限或角色功能? 6.责任链模式:处理权限验证的链式检查? 7.组合模式:角色可能有层级结构,比如角色 可以包含子角色,这时候组合模式适用。 例如,权限管理可能需要组合模式,如果角色 可以继承其他角色的权限,那么组合模式可以 帮助构建树形结构。但是用户提到角色多达几 十种,可能每个角色都是独立的,或者存在层 级关系。需要明确这点。如果角色之间有继承 关系,那么组合模式更合适,否则可能不需 要。 接下来,权限的分配可能需要策略模式,不同 的角色分配权限的方式不同。或者使用访问控 制列表(ACL)的方式管理权限。或者每个权 限对应一个唯一的字符串或枚举,角色拥有这 些权限的集合。 用户管理模块需要实现基本的CRUD操作:创 建用户、删除用户、修改用户信息、查询用 户。角色和权限同样需要类似的CRUD操作。 权限可能不需要修改,但角色可能需要动态调 整权限。 关于大规模应用,角色多的话,需要高效的查 询和存储结构。比如使用数据库关联表来管 理用户-角色关系和角色-权限关系。用户表、 角色表、权限表,然后用户-角色中间表,角 色-权限中间表。这样在数据库设计上是标准的 多对多关系。 在代码结构上,可以分层设计:表现层(GUI或 Web)、业务逻辑层、数据访问层。业务逻辑 层处理用户、角色、权限的管理逻辑,数据访 问层负责与数据库或文件交互。 设计模式的应用方面,数据访问层可以使用 DAO模式,每个实体(用户、角色、权限)对 应一个DAO接口和实现。比如UserDao、 RoleDao、PermissionDao,然后针对不同的 存储方式(数据库或文件)有不同的实现。这 里可以用抽象工厂模式,根据配置生成不同的 DAO工厂,进而得到不同的DAO实现。 例如,定义一个DaoFactory接口,里面有 createUserDao(), createRoleDao()等方法。 然后DatabaseDaoFactory和FileDaoFactory 分别实现这个接口,生成对应的数据库或文件 操作的DAO。这样在切换存储方式时,只需更 换工厂类即可,符合开闭原则。 权限的验证可能在业务逻辑层处理。比如检查 用户是否有某个权限时,需要遍历用户的角 色,再累加这些角色的权限。这里可能需要缓 存用户的权限,以提高性能,尤其是当角色很 多时。 另外,考虑角色和权限的缓存,比如使用缓存 模式,将角色对应的权限缓存在内存中,减少 数据库查询次数。 类图方面,大概会有User、Role、Permission 三个实体类。每个User可以有多个Role,每个 Role可以有多个Permission。然后是 UserDao、RoleDao、PermissionDao接口及 其实现类。UserService、RoleService等业务 逻辑类,处理具体的业务操作,比如分配角 色、检查权限等。 设计模式方面,DAO模式是必须的,工厂模式 用于创建DAO,可能策略模式用于切换不同的 存储策略。组合模式如果角色有层级结构的 话。观察者模式用于权限变更的通知,比如记 录日志或者通知其他系统模块。 代码结构大致如下: • model包: User, R
03-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值