hibernate多表操作详解

来源:互联网 发布:base64.js下载 编辑:程序博客网 时间:2024/06/06 17:17

一.简介

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


建表原则

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

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

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

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

class Aclass Aclass A
{{{
B b;Set<B> bs;Set<B> bs}}}class Bclass Bclass B
{{{
A a;Set<A> asA 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 获得sessionSession 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操作。