Hibernate实战_笔记3

来源:互联网 发布:网站运营数据指标 编辑:程序博客网 时间:2024/06/06 00:48

与关联相关的问题

      在领域模型中,关联表示实体之间的关系。面向对象的语言利用对象引用(object reference)表示关联;但是在关系领域中,关联则被表示为外键(foreign key)列,这两种表示法之间有着本质的区别。

      对象引用具有固有的方向性;关联是从一个对象到另一个对象。它们是指针。如果对象之间的关联应该在两个方向导航,就必须定义两次关联,在每个关联的类中定义一次。你已经在领域模型类中见过:

public class User{private Set billingDetails;...}public class BillingDetails{private User user;...}

      另一方面,外键关联不是生来就有方向性。导航(navigation)对于关系型数据模型没有任何意义,因为可以用表联结(table join)和投影创建任意的数据关联。

      不可能只看Java类就确定一个单向关联的多样性。Java关联可以有多对多(many-to-many)的多样性。例如,类可以看起来像下面这样:

public class User{private Set billingDetails;...}public class BillingDetails{private Set users;...}

      另一方面,表关联始终是一对多(one-to-many)或者一对一(one-to-one)。通过查看外键的定义,你立即就会知道多样性。

      你如果想在一个关系数据库中表示一个多对多的关联,就必须引入一张新表,称作链接表(link table)。这个表不会出现在领域模型中。对于我们的例子来说,如果认为用户和帐单信息之间的关系为多对多,链接表就可以定义如下:

create table USER_BILLING_DETAILS(USER_ID bigint foreign key references USERS,BILLING_DETAILS_ID bigint foreign key references BILLING_DETAILS,PRIMARY KEY(USER_ID,BILLING_DETAILS_ID));

数据导航的问题

在Java和在关系数据库中访问数据的方式有着根本的区别。在Java中,当你访问用户的帐单信息时,调用aUser.getBillingDetails().getAccountNumber()或者类似的东西。这是访问面向对象的数据最自然的方式,通常称作遍历对象网络。跟着实例之间的指针,从一个对象导航到另一个对象,不幸的是,这并不是从SQL数据库中获取对象的有效方法。      
      为了提高数据访问代码性能,你能做的最重要的事情就是将请求数据库的次数减到最少。最明显的做法是将SQL查询的次数减到最少。

      因此,使用SQL有效地访问关系型数据通常需要在有关的表之间使用联结。获取数据时联结中包括的表数目决定了能够在内存中遍历对象网络的深度。例如,如果需要获取 一个User,而对用户的帐单明细不感兴趣,可以编写这个简单的查询:

select * from USERS u where u.USER_ID = 123

      另一方面,如果需要获取一个User,随便访问每个关联的BillingDetails实例(比如,列出用户的所有信用卡),可以编写一个不同的查询:

select *from USERS uleft outer join BILLING_DETAILS bd on bd.USER_ID = u.USER_IDwhere u.USER_ID = 123;

      另一方面,只有当对象被初次访问时,所有对象持久化解决方案才提供抓取关联对象的数据的功能。然而,这种渐进风格(piecemeal)的数据访问在关系数据库的上下文中效率很低,因为它要给每个节点或者每个被访问的对象网络的集合执行一条语句。这就是可以的n+1查询问题(n+1 select problem)。
在Java和关系数据库中访问对象的这种不匹配,可能是Java应用程序中性能问题的一个最普通的根源。

不匹配的代价

      现在已经有了相当一些对象/关系不匹配问题,你可能凭经验就知道,找到这些解决方案的代价不菲(时间和精力)。这种代价通常被低估了,这是许多软件项目失败的主要原因。
      主要的成本之一在于模型化方面。关系和领域模型都必须包含相同的业务实体,但是一位面向对象的纯化论者给这些实体建模的方法 ,与一位经验丰富的关系型数据建模者给出的不同。这个问题通常的解决方案是扭曲领域模型和被实现的类,直到它们与SQL数据库Schema相匹配。(遵循数据独立独立的原则,必定是个安全的长久之计。)
这可能会成功,但要以失去面向对象的一些优势为代价。记住,关系模型以关系理论为基础。面向对象则没有这样严格的数学定义或者理论主体,因此我们无法用数学来解释应      该如何为这两种范式建立某种关系 ——没有优雅的转化等着被发现。
领域模型不匹配并不是低灵活性和导致更高成本的低生产力的唯一根源。更深层次的原因是JDBC API本身。JDBC和SQL提供了一个面向语句的方法,把数据从SQL数据库移进移出。如果要查询或者操作数据,涉及的表和列至少必须被指定3次(插入,更新,选择),这增加了设计和实现所需要的时间。


笔记1~3总结:

刚开始学Hibernate,正好老师给了一本Hibernate的电子书,就打算花些时间学习深入下。

这3段笔记中,主要从为什么持久化、SQL认知、面向对象操作SQL到领域模型与关系模型范示的不匹配。

主要对领域模型与关系模型范未的不匹配总结如下:

1、粒度问题

就像例子中所说的User类为粗粒度,而Address为细粒度,当然Address也可以分解成多个属性放置User类中,但是如果有多个实体类需要引用Address类的话,将Address设计成一个单独的类,更是恰当。

2、子类型问题

1)继承映射主要有一颗继承树映射单独的一张表(操作方便,就是如果子类字段多了之后,可以表中出现非常多的NULL字段)

2)父类单独映射到一张表,子类各自映射到一张表,且子类引用父类中的公共字段(查询操作需要涉及到多张表的)

3)每个具体类,映射成一张表(比如说有A父类、B子类、C子类,就是说A父类+B子类映射一张表、A父类+C子类映射一张表,不过说到底如此映射增、删、改只需操作一张表,但查询的话得多张表咯)

3、同一性问题

领域模型引用对象、equals()方法

关系模型使用代理键(即ID)

4、与关联相关的问题

领域模型通过对象引用实现关联关系

关系模型则通过外键来实现关联关系

5、数据导航的问题

领域模型通过遍历对象网络实现数据导航

关系模型则通过表连接实现数据导航

嘿嘿,总结了一下,今天下午没算白费,大家有问题的一起交流呼呼。

3 0
原创粉丝点击