- 浏览: 93160 次
文章分类
最新评论
-
307483857:
微软不给他们钱,他们也会这么干的,,,这不明摆着的事情吗,不支 ...
硬件厂商正配合微软强制我们使用WIN7,WIN8! -
shishangq:
晕,好多种关系都没用过。。。
Hibernate映射解析——七种映射关系 -
hongqiang:
不错@~写的很详细
Hibernate映射解析——七种映射关系 -
lucky16:
还是比较详细的...
Hibernate映射解析——七种映射关系 -
巴巴米:
用的竟然是rose吗。。好久没见过这个东西了。
Hibernate映射解析——七种映射关系
关系总体分为三种:一对多,多对多,一对一.在配置映射文件时, 需要选择与保存对象相应的集合标签.
在一对多的关系中,往往只需要一方维护两者的关系,因为在关系型数据库中,只需要有一方存储关系就行了,称为外键,外键列保存在多的一方即可,对于对象来说,双方都设置关联才比较好,这样双方才都知道与对方关联,但是对于数据库来说,只需要一方设置有关联就可以了,不管哪一方,只进行设置,默认就会生成一条update语句来更新外键的值,以保存关联关系(维护关联关系),如果关联一个没有保存的对象(有效的关联),会抛出一个TransientObjectException异常.不管在哪一方都能找到另一方,称为双向关联,单项关联就是指仅仅从某一方才能找到另一方,而另一方不能找到某一方,因为在另一方的数据库中没有维护关系,自然就找不到.关联关系中重要的属性:
- inverse:是否只由对方维护关联关系,默认值为false.对于一对多,维护关联关系是指更新外键列的值,对于多对多,维护关联关系是指在中间表中插入或删除记录,这个属性只在表示关联关系的集合映射中用(一对多、多对多)
- cascade:级联操作,即对从对象也做相应的操作,级联风格有:save-update, delete, none, all, delete-orphan, all-delete-orphan, ...,默认值为none.只要是关联关系,都可以配这个属性(一对多、多对一、多对多、一对一)
- order-by:指定排序子句(order by子句,是指定的sql语句,所以要写列名,这个属性可以在所有的无序集合映射中使用(<set>中可以用,<list>中不可以用),模拟一的一方:
<!-- 不用指定表名,因为根据类,可以自动找到映射文件,映射文件里有描述表的结构 cascade="all":将一个关联关系(无论是对值对象的关联,或者对一个集合的关联) 标记为父/子关系的关联。 这样对父对象进行 save/update/delete 操作就会导致子对象也进行 save/update/delete 操作
lazy:默认值为true,开启懒加载.属性interests是set集合的引用,这个集合里面的对象存在数据库中,是person对象的子对象,
如果开启懒加载,且没有在session关闭之前访问interests的成员,则关闭session之后就获取不到了,访问将抛LazyInitializationException异常.--> <set name="interests" cascade="all"> <key column="personID"></key> <one-to-many class="..domain.Interest"/> </set>
多的一方:
<!-- |
很贴切的标签 |
name:指定对应的属性 |
column:指明外键列的列名 |
--> |
<many-to-one class="..domain.Person" name="person" column="personID"></many-to-one> |
假设我有一个员工表,和一个部门表,我有15个员工和5个部门,它们的关系在数据库中表示为员工表的外键列,在session开启之后获取到部门的持久对象,也将获取和它关联的员工,在session关闭之前所做的任何修改都将直接同步到数据库中.如果要解除两者的关联关系:
// 解除关联关系 |
@Test |
public void testRemoveRelation() { |
Session session = sessionFactory.openSession(); |
Transaction tx = session.beginTransaction(); |
// -------------------------------------------------------------- |
// Employee employee = (Employee) session.get(Employee.class, 15); |
// employee.setDepartment(null); |
Department department = (Department) session.get(Department.class, 5); |
// department.getEmployees().remove(obj); // 与指定的员工解除关联关系 |
// department.getEmployees().clear(); // 与关联的所有员工解除关联关系 |
// department.setEmployees(null); // 与关联的所有员工解除关联关系 |
department.setEmployees(new HashSet<Employee>()); // 与关联的所有员工解除关联关系 |
// -------------------------------------------------------------- |
tx.commit(); |
session.close(); |
} |
删除部门时,如果有和它关联的员工,则可能会有约束异常,必须先把与员工的关系解除或者连员工一起删除,需要设置cascade属性,然后才能进行:
@Test |
public void testDelete() { |
Session session = sessionFactory.openSession(); |
Transaction tx = session.beginTransaction(); |
// -------------------------------------------------------------- |
/** 删除部门时,如果有员工引用这个部门的id,则: |
a,如果inverse=true,即不能维护关联关系,就会 抛异常: Cannot delete or update a parent row: a foreign key constraint fails |
b,如果inverse=false,即可以维护关联关系,则Hibernate会先取消与所有员工的关联,再删除部门,不会有异常。 |
先获取持久对象,用get()方法或者load()方法,或者自己模拟一下: |
Department department = new Department(); |
department.setId(4); |
只要OID对应即可. |
*/ |
Department department = (Department) session.get(Department.class, 4); |
session.delete(department); |
//department.getEmployees().clear(); // 解除与所有关联员工的关联关系 |
// -------------------------------------------------------------- |
tx.commit(); |
session.close(); |
} |
多对多的关联关系比多对一的关联关系更好理解一些,通常在数据库中有张中间表来描述:
在Hibernate中默认双方都能维护关联关系,但双方都设置关联关系会有异常:java.sql.BatchUpdateException.因为中间表通常以两个外键作为联合主键,在程序中,由于是多对多的关系,双方维护的对象都是一样的,比如:
从任何一方都能关联,任何一方都清楚的展示了对方的属性,任何一方的对象里面都维护着另一方的对象(双向关联),这样一来,在持久化对象的时候,就会在中间表中出现重复记录,当然是不允许的.所以一般做法为:只关联一方或者在某一方设置inverse=”true”即可.多对多是关联关系里面用的最多的:
<!-- 多对多映射(employees : Set<Employee> 属性) |
<key column="..."/>是配置集合外键,即引用当前对象表的主键的那个外键 |
inverse="true"表示放弃维护关联关系(由对方维护)。在多对多中,维护关联关系是指的在中间表中插入一条数据 |
--> |
<set name="employees" table="emmployee_role" inverse="true"> |
<key column="roleId"></key> |
<many-to-many class="Employee" column="employeeId"></many-to-many> |
</set> |
一对一.一对一虽然不难,理解起来比多对多稍微麻烦一点,假设一个部门只能有一个员工,一个员工也只能有一个部门.一对一有两种映射方式:
基于主键(推荐)
这是一种万能方式,因为employee表中的主键是id,属于代理主键,如果开发部被删除了,zhang将不会被删除,因为department_id可能设置允许为null.
有外键的表的映射文件(employee):
<!-- |
这里用到了多对一的标签,但是这里并不是指的多对一,从unique属性就能看出来这一列的记录不能重复,那 |
为什么要用这个标签而不是one-to-one呢?因为这张表需要一个保存其他表数据的外键列,而one-to-one |
标签不会生成一个外键列,所以需要用到many-to-one标签,并且给它设置unique属性让它唯一,因而也可 |
以认为一对一只是多对多的一种特例.给它加上cascade属性是为了更方便的管理对象,如果子对象没有持久 |
化,也自动给它持久化 |
--> |
<many-to-one cascade="all" |
unique="true" name="department" |
class="..domain.Department" |
column="departmentID"> |
</many-to-one> |
无外键表的映射文件(department):
<!-- |
表中不需要维护两个相同的记录,需要获取时一并获取即可,无外键方,使用<one-to-one> |
property-ref:默认与被关联的实体的主键相关联,有了property-ref属性, |
就可以通过它与被指定的实体主键以外的字段相关联 |
--> |
<one-to-one name="employee" property-ref="department" class="..domain.Employee"></one-to-one> |
基于外键
在这种方式下,employee表中的id既当主键又当外键,如果开发部被删除了,zhang也要被删除,因为主键不能为null,与其他对象有多个一对一关系时,如果外键设计在当前表中,则最多只能有一个基于主键的一对一映射.有外键方的对象需要独立存在而不与对方的某一条数据关联时,不能使用基于主键的一对一映射.除非保证employee表中的id始终有值对应.除了这些以外,还需要在两者之间寻找主从关系,比如人是必须存在的,身份证需要依赖人,人就是主,身份证就是从.
主:
<!-- |
只需要描述自己的idCard属性所对应的对象即可 Hibernate会自动找到对应的映射文件 |
--> |
<one-to-one name="idCard" class="..domain.IdCard"></one-to-one> |
从:
<!-- |
因为自己的主键也是外键,一张表中可以存在多个外键, 所以必须说明自己的主键是参照哪个外键 |
--> |
<id name="id"> |
<generator class="foreign"> |
<param name="property">person</param> |
</generator> |
</id> . . . |
<!-- |
constrained:是否加上外键约束,默认值为false |
--> |
<one-to-one name="person" class="..domain.Person" constrained="true"> |
</one-to-one> |
不管关联关系是什么,不是谁都能维护关联关系,关于谁才能维护关联关系:
一对多:
默认双方都能维护
在一方可以通过设置inverse="true"来放弃维护关联关
在多方(有外键方)始终能维护关联关系,因为外键在自己表中
多对多:
默认双方都能维护
在任何一方都可以通过设置inverse="true"来放弃维护关联关系。注意只需设置一边就可以
一对一:
不管是采基于外键的还是基于主键的一对一映射,都是只有有外键方可以维护关联关系,没有外键方不可以维护。而且不可以配置
当采用基于主键的一对一映射时,双方都不能解除关联关系,因为主键值为能为null
单向关联与上述的一致,能维护关系的一方才可以做单向关联到对方.
继承映射
映射继承结构的时候,一般是整个继承结构使用一个映射文件,名称前缀为超类的名,继承映射有三种方式,全部以论坛的帖子为例:
方式一:
一个继承结构只有一张表,同时只有一个映射文件,那它的子类怎么办?用<subclass>标签配置它的子类.另外分析下,因为是一张表,表中要有所有的字段,但是主题的帖子肯定不需要floor(楼层),只有回复表才需要标注自己是几楼,同理,主题的extra(如精华、置顶...)也是主题表特有的.那么如何判断帖子是什么类型呢?判断帖子有extra,则是主题,有floor,则是回复等,所有可能情况如下:
前两条记录还好说,第三条怎么算呢?可能是一个没有extra的主贴,也有可能是一个没有标注楼层的回复,总之,从设计表的结构上就要把这种可能性排除,所以采用中表中加入一个type来指定具体的类型.那么,如果把类型在添加记录的时候就加入进来呢?不同类型的对象添加的时候自然就是不一样的值,比如主题就是type=topic,回复就是type=reply.如下:
<hibernate-mapping package="..mapping"> |
<!-- 一个继承结构一张表的映射方式: |
需要有一个额外的列用于保存类型标志。 |
每个类都需要指定discriminator-value属性,表示代表当前类型的标志。如果没有指定,默认为当前类的全限定名。 |
父类与子类只需要映射自己的属性就可以了。 |
--> |
<class name="Article" table="Article" discriminator-value="Article"> |
<id name="id"> |
<generator class="identity"></generator> |
</id> |
<!-- 指定用于辨别是什么类型标志列 必须放在property标签之前--> |
<discriminator column="type_type="string"></discriminator> |
<property name="title"></property> |
<property name="content"></property> |
<!-- 子类:Topic --> |
<subclass name="Topic" discriminator-value="Topic"> |
<property name="extra"></property> |
</subclass> |
<!-- 子类:Reply --> |
<subclass name="Reply" > |
<property name="floor"></property> |
</subclass> |
</class> |
</hibernate-mapping> |
方式二:
每个类一张表,抽象类也有表(<joined-subclass>),子类表与父类表是一对一的关系,在映射时,每个类都只映射自己特有的属性,公共的属性值存放在父类表中,父类表的主键和子类表的主键相关联,不相关的子类表,不添加记录:
<hibernate-mapping package="..mapping"> |
<!-- 每个类一张表 |
子类表与父类表是一对一的关系 |
在映射时,每个类都只映射自己特有的属性 |
--> |
<class name="Article" table="Article"> |
<id name="id"> |
<generator class="identity"></generator> |
</id> |
<property name="title"></property> |
<property name="content"></property> |
<!-- 子类:Topic |
需要指定表名。 |
需要指定<key column="id"></key>,表示自己的主键,且是外键引用父类表的主键(一对一的关系) |
--> |
<joined-subclass name="Topic" table="Topic"> |
<key column="id"></key> |
<property name="type"></property> |
</joined-subclass> |
<!-- 子类:Reply --> |
<joined-subclass name="Reply" table="Reply"> |
<key column="id"></key> |
<property name="floor"></property> |
</joined-subclass> |
</class> |
</hibernate-mapping> |
<hibernate-mapping package="..mapping"> |
<class name="Article" table="itcast_Article"> |
<id name="id"> |
<generator class="hilo"> |
<param name="table">hi_value</param> |
<param name="column">next_value</param> |
<param name="max_lo">100</param> |
</generator> |
</id> |
<property name="title"></property> |
<property name="content"></property> |
<!-- 子类:Topic |
需要指定表名。 |
--> |
<union-subclass name="Topic" table="topic"> |
<property name="type"></property> |
</union-subclass> |
<!-- 子类:Reply --> |
<union-subclass name="Reply" table="reply"> |
<property name="floor"></property> |
</union-subclass> |
</class> |
</hibernate-mapping> |
关于Hibernate的查询,有多种方式:
-
根据OID查询(get()与load())
-
导航对象图检索方式: 根据已经加载的对象导航到其他对象
-
HQL(Hibernate Query Language)
-
QBC(Query By Criteria)
HQL
命名查询
Query query = session.getNamedQuery("queryAllEmployees");
List list = query.setParameter(0, 5).list();
对应的配置文件:
<!-- 定义命句查询语句 -->
<query name="queryAllEmployees">
<!--[CDATA[FROM Employee WHERE id>?]]-->
</query>
如果执行一条查询,查询出了多个结果,则会抛NonUniqueResultException异常.
发表评论
-
Hibernate映射解析——七种映射关系
2012-07-19 13:10 4199首先我们了解一个名词ORM,全称是(Object Relati ... -
Hibernate 中get, load 区别
2012-04-22 15:29 6411. 对于get方法,hibernate会确认一下该id ... -
一点点学习Hibernate3.6 -二级缓存
2012-04-22 15:28 946Hibernate中提供了两个级别的缓存: 一级缓存是 ... -
一点点学习Hibernate3.6 -Criteria(面向对象的查询)
2012-04-19 23:02 934// 1,简单查询(查询所有的Employee) ... -
一点点学习Hibernate3.6 -事务管理
2012-04-19 23:01 993Hibernate的事务(Transaction)使用的 ... -
一点点学习Hibernate3.6 -对象的状态
2012-04-19 23:00 879hibernate的设计者为 ... -
一点点学习Hibernate3.6
2012-04-19 22:59 744框架的诞生必然是为了解决某一问题,要对Hibernate ...
相关推荐
Hibernate3.6-Final-CHM带搜索API
【hibernate3.6-jar包】是一个与Java编程相关的资源,主要涉及ORM(对象关系映射)框架Hibernate的3.6版本。Hibernate是一个开源的库,它允许开发人员在Java应用程序中使用面向对象的方式来操作数据库,从而避免了...
Hibernate 是一个广泛使用的开源对象关系映射(ORM)框架,它为Java开发者提供了便捷的方式来处理数据库操作。在 Hibernate 3.6 版本中,这个框架继续强化了其在简化数据库访问、提高开发效率以及支持多种数据库平台...
hibernate3.6 对应的 hibernate-validator-4.1.0
在"hibernate-father-son"这个例子中,可能包含两个实体类,如"Father"和"Son","Father"与多个"Son"之间存在一对多关系。在实际开发中,这种关系映射可以方便地处理父子级联操作,如级联保存、更新和删除。 四、...
《Hibernate 3.6 中文 CHM》是一个针对Hibernate 3.6版本的详细使用指南,旨在帮助开发者理解和掌握这个强大的对象关系映射(ORM)框架。Hibernate是Java开发中的一个重要工具,它允许程序员以面向对象的方式处理...
- **一对一连接表关联**:通过一个额外的连接表来实现两个实体之间的一对一关系。 2. **一对多关联**: - **一对多外键关联**:一个实体包含指向多个其他实体的外键。 - **一对多连接表关联**:通过一个连接表来...
8. **关联映射**:Hibernate 支持多种关联类型,如一对一(OneToOne)、一对多(OneToMany)、多对一(ManyToOne)、多对多(ManyToMany),以及集合关联(List, Set, Map等)。 9. **继承映射**:Hibernate 提供了...
此外,`hibernate-mapping-3.0.dtd`还支持更复杂的映射,如一对一、一对多、多对多的关系映射,以及自定义类型、延迟加载等特性。 在实际应用中,`hibernate.properties`文件是Hibernate 5.0.7版本的配置文件,主要...
9. **关联映射**: Hibernate支持一对一、一对多、多对一、多对多等关联映射,可以方便地处理对象间的复杂关系。 10. **事件监听**: Hibernate提供了一些事件接口,如PreInsertEvent、PostUpdateEvent等,可以通过...
Hibernate 3.6 是一个流行的Java对象关系映射(ORM)框架的重要版本,它极大地简化了数据库操作,将复杂的SQL语句与Java对象之间建立了桥梁。在这个版本中,Hibernate提供了许多增强的功能和优化,旨在提高开发效率...
Hibernate 3.6 Final所有的jar包,以及Hibernate Tools 中的hibernate-tools.jar 和 freemarker.jar 。 本jar包用于使用hibernate-tools生成POJO所需要的依赖库
在Hibernate中,一对一唯一外键关联映射是指两个实体之间的关联关系,其中一个实体作为外键,另一个实体作为关联目标。这种关联方式可以分为单向关联和双向关联两种。 单向关联是指一个实体作为外键,关联到另一个...
对于一对一关系,Hibernate同样会自动处理关联的插入和删除。添加员工到部门,只需要设置部门属性即可;查询时,可以通过`List`或`Set`获取子对象。 总结 Hibernate5的映射关系极大地简化了数据库操作,使得开发者...
jar包,官方版本,自测可用
jar包,官方版本,自测可用
【hibernate的关联关系映射】在Java持久化框架Hibernate中,关联关系映射是核心功能之一,它允许对象间的复杂关系与数据库中的表结构相匹配。在选课系统这个例子中,主要涉及到的对象包括课题(Course)、教师(Teacher...
jar包,官方版本,自测可用