hibernate多表操作详解

一.简介

在进行关系型数据库设计时,表与表之间的关系往往不是独立的,而是相互关联的,这就是所谓的多表设计。一般来说,数据库表与表包含以下几种关系。


建表原则

一对一:主键对应,一方的主键作为另一方的主键。

一对多:在多的一方创建外键指向一的一方的主键

多对多:创建一个中间表,中间表的最少两个字段作为外键分别指向多对多双方的主键。

此种关系在hibernate中用Java对象表示如下:

	class A				class A					class A
	{				{					{	
		B b;				Set<B> bs;				Set<B> bs
	}				}					}
	class B					class B				class B
	{				{					{	
						A a;					Set<A> as
		A a;			}					}
	}		
	一对一的关系			一对多的关系				多对多的关系

在一般情况下,一对多的情况是比较常见的,比如学生与老师的关系,部门与员工的关系,客户与联系人的关系,所以,下面将以一对多关系为例说明hibernate是怎么建立多表之间的关系的。

二.hibernate的一对多关系映射操作实例

1.例子说明:

本实例建立两个表,分别是联系人表和客户表(典型的客户管理系统中经常遇到的),其中一个客户拥有多个联系人,即客户与联系人的关系为一对多。所以,联系人中存在外键,该外键指向客户。具体描述如下。

2.创建hibernate实体

联系人实体

	public class LinkMan {
		private Long lkm_id;
		private Character lkm_gender;
		private String lkm_name;
		private String lkm_phone;
		private String lkm_email;
		private String lkm_qq;
		private String lkm_mobile;
		private String lkm_memo;
		private String lkm_position;
	
		//注意这里是关键写法,在多的一方的实体中创建一个类型为一的一方的属性
		private Customer customer ;
		get方法....
		set方法....
	}
客户实体

	public class Customer {
		private Long cust_id;
		private String cust_name;
		private String cust_source;
		private String cust_industry;
		private String cust_level;
		private String cust_linkman;
		private String cust_phone;
		private String cust_mobile;
		//注意这里是关键,在一的一方的实体中创建一个泛型类型为多的一方的set集合。
		private Set<LinkMan> linkMens = new HashSet<LinkMan>();
	}
2.创建映射关系

联系人映射关系的写法(多的一方)

前面普通字段不再累述,可参见笔者前一篇博客。重点讲述关联对象的配置。一的一方使用many-to-one元素。

<many-to-one name="customer" column="lkm_cust_id" class="Customer的完整类名"  >
</many-to-one>
name属性:引用属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名


客户映射关系的写法(一的一方)

多的一方使用set元素来描述被映射类的set集合,

<set name="linkMens"   >
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan的完整类名" />
</set>
key标签的column属性:用来描述对应文件多的一方的主键名称。

one-to-many元素 的class属性:用来描述映射关联类

3.将映射添加到hibernate主配置文件中

<mapping resource="Customer.hbm.xml文件的包路径" />
<mapping resource="LinkMan.hbm.xml的包路径" />
4.编写测试函数

public void text(){
		//1 获得session
		Session session = HibernateUtils.openSession();
		//2 开启事务
		Transaction tx = session.beginTransaction();
		//-------------------------------------------------
		//创建一个客户
		Customer c = new Customer();
		c.setCust_name("谷歌");
		//创建多个联系人
		LinkMan lm1 = new LinkMan();
		lm1.setLkm_name("crc");
		LinkMan lm2 = new LinkMan();
		lm2.setLkm_name("psl");
		
		//表达一对多,客户下有多个联系人
		c.getLinkMens().add(lm1);
		c.getLinkMens().add(lm2);
		
		//表达对对对,联系人属于哪个客户
		lm1.setCustomer(c);
		lm2.setCustomer(c);
		//若无设置级联操作,则所有对象均要保存,否则出现瞬时对象异常。
		session.save(c);
		session.save(lm1);
		session.save(lm2);
		
		//4提交事务
		tx.commit();
		//5关闭资源
		session.close();
	}
若制定Junit测试后为绿条,且数据库新创建两个表,说明hibernate执行多表关联操作成功。

三.hibernate多表关系映射的级联操作

所谓级联操作是指当主控方执行保存,更新,删除操作时,其关联的对象也会执行相同的操作。在映射文件中通过set元素的

属性cascade来配置。主控方的选择是任意的,但一般习惯主控方选择为一的一方。

1.级联保存,关键词为save-update

配置如下代码:

<set name="linkMens" cascade="save-update"  >
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
</set>
此时,只要执行保存客户,联系人会跟着保存下来。

2.级联删除,关键词为delete

配置代码如下

<set name="linkMens"  cascade="delete"  >
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
</set>

这时,在代码中删除了客户,与其关联的联系人也会跟着删除,但是,要注意,这种操作比较危险,一般不用

要注意,级联保存和级联删除是可以同时配置 的。

四.双向关联产生多余的SQL语句 的问题

在实行表对象关联时操作时,SQL语句有可能会重复执行,出现这种问题的原因是,两个表对象都维护了关系,持久化对象可以自动更新数据库,更新客户时会修改一次外键,更新联系人时也会修改一次外键,因此产生多余的SQL语句。解决方法是使其中一方放弃维护关系即可。一般情况下,一的一方放弃维护关系。执行如下配置即可。

<set name="linkMens" inverse="true" cascade="delete,save-update"  >
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
		</set>
		
inverse的默认值为false,代表不放弃外键维护权,修改为true,即放弃维护。(注意, 这一点与我们的正常思维相反

五.总结

数据库的多表设计问题是一个重要的知识点,本博客以一对多关系为例,介绍了hibernate中的多表操作。感兴趣的朋友可以

深入研究多对多的表关系,或者三表以及更多表的hibernate操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值