文档章节

一对一映射的三种方式以及对lazyload的特别关注

猪刚烈
 猪刚烈
发布于 2014/10/12 11:41
字数 1754
阅读 20
收藏 0

      一对一映射几乎涉及了所有可以使用的映射方式:共享主键、外键和关联表。每一种方式都有相对特定的使用场合。而与此同时,one-to-one关系的 lazy loading总是一个让人非常疑惑的问题,下文在介绍每一种一对一映射方案的时候也会对lazy loding的问题做一个说明。


 一.共享主键方式


     这是一对一方案所特有的一种映射方式,这种方式特别适合非空的并且具有一致生命周期(同生同灭)的一对一关系。以User,Address为例,我为 Address的主键再添加一个外键,来参照User,这样就是声明让Address做“受约束”端,也就是constrained="true"的那一端。关于constrained="true"我们会在后面作出解释。下面是表关系:

User端的映射较为简单:

      @OneToOne
      @PrimaryKeyJoinColumn
      private Address shippingAddress;

Address端相对复杂,因为我们需要在配置中指明它的主键生成策略,这个策略是要参照User主键的。

@Entity @Table(name = "ADDRESS") 
public class Address { 
	@Id @GeneratedValue(generator = "myForeignGenerator") 
	@org.hibernate.annotations.GenericGenerator( 
		name = "myForeignGenerator", 
		strategy = "foreign", 
		parameters = @Parameter(name = "property", value = "user") ) 
	@Column(name = "ADDRESS_ID") 
	private Long id; 
	...
	private User user; 
}

       下面来讨论一个使用共享主键方式的lazy loding问题。在上面的例子中,其实很容易知道Address的user字段是可以lazy loding的,而User和shippingAddress是不能的!为什么呢?因为外键在Address表上,当load一条Address记录时,它能从外键上确定有没有关联对象,从而能确定是生成代理对象还是一个null,反观 User,由于它没有外键参照到Address,这样,在加载User时,无法通过User本身的纪录来判定它有没有一个对应的Address,进而无法确定是生成一个代理还是一个null值,因此,hibernate必须hit数据库(往往是在加载时直接使用left join一起把address也查出来).


      在基于xml配制的方式下,one-to-one有一个配制项:constrained="true"。JPWH一书566页曾提及:在共享主键方式的映射方式中,只有在one-to-one中标记了constrained="true"那个关联对象才是可以被lazy loading的。下面是Address的xml配置:

<class name="Address" table="ADDRESS"> 
	<id name="id" column="ADDRESS_ID"> 
	<generator class="foreign"> <param name="property">user</param> </generator> </id>
	...
	<one-to-one name="user" class="User" constrained="true"/> 
</class>


官方文件对constrained的解释是:


  在解释这一配置项之前必须声明两个概念:关联方和被关联方。关联方是当前正在配置的类,被关联方是指当前被配置的字段所属的类(在Address的 user字段配置上,关联方就是Address,被关联方就是user)。那么,constrained=“true”的解释就是:它指明在关联方表的主键上会同时有一个外键,这个外键指向被关联方表的主键。简单说,它指明外键是放在关联方上的。这样,对于关联方来说,当它加载时,它就可以通过外键列来确知被关联方存不存在,进而确保了在关联方加载时,被关联方能否被lazy loading。


  实际上在注解方式下是没有也不需要这一选项的,映射了使用外键策略生成主键的对象(也就是主键同时做外键的表)应该自动具有了lazy lode另一端关联对象的能力。


二,外键映射方式


  这种方式是通过对外键列加unique约束来模拟一对一关联,这种映射方法较为简单,是被推荐的做一对一映射的最自然方式。还是以User,Address为例:在User端的注解配置是:
public class User {
    ...
    @OneToOne
    @JoinColumn(name="SHIPPING_ADDRESS_ID",unique=true)//unique=true确保了一对一关系
    private Address shippingAddress;
    ...
}

 

  需要特别说明的是:从外键的角度来看,虽然从User到Address是一个加了unique约束的“多对一”的关系,但是在使用注解时,JPA规范还是要求使用@OneToOne。在hibernate的xml配置方式中,这里就不会写<one-to-one>,而是写成了:其实这种写法更能揭示配置的本质。
Address端的注解配置是:
public class Address {
    ...
    @OneToOne(mappedBy = "shippingAddress")
    private User user;
    ...
}
  OK,那我们回过头来看lazy loading的问题。这与共享主键方式非常相似,外键所在的那一方,也就是many方,也就是有@JoinColumn的那一方,它可以lazy loading,而另一方则不能!(已经代码验证!)


三.关联表映射方式


  我们可以看到,由于关联表方式,关联双方都没有指向对方的外键,因些,在这种方式下,双方都不可能是lazy loading的。
下面是Desk的user字段映射配置。从实际代码执行中可以确定:fetch=FetchType.LAZY是无效的。

    @OneToOne(fetch=FetchType.LAZY)
    @JoinTable(
        name="Desk_Employee",
        joinColumns=@JoinColumn(name="deskId"),// You did't specify this column as primary key, but it's set primary key auto!
        inverseJoinColumns=@JoinColumn(name="employeeId",unique=true)//unique=true make sure one-to-one relationship.
    )



总结


最后对一对一三种映射方式做一个简单的总结:
  1.共享主键方式适合那些关联双方不能为空,且永远不会发生变化的一对一关系。对象模型来看,大部分这类情形应该双方具有同等生命周期的组成关系。
  2.外键关联加唯一约束的方式适合非空,但关连双方会发生成变化的一对一关系。这显然是聚集和一般的关联关系。
  3.关联表方式无疑最为灵活,它适合会经常发生变化并且可以为空的一对一关系。典型的场景就是桌子和员工的分配问题。一张桌子总是对应一个员工,但并不总是一个特定的员工,有时候会发生调换,有时候可能没有人使用,而员工方面也是如此。另外一个例子是JPWH一书中提到的Item和Shipment之间的一对一关系。一个物品一旦售出,就会生成一个运送记录,用于追踪商品的运送过程。这个例子和桌子员工的情形有细微不同的地方在于,桌子和员工之间的关系还存在一种可变更的情况, 而Item和Shipment之间只是一个可选的一对一关系,也就是说只有Item售出才会生成一条Shipment,并不是所有Item一定会有一个对应的Shipment!实际上这正是JPWH一书在映射Item和Shipment时选择使用关联表的最主要原因,因为共享主键方式肯定不行,而外键关联方式则需要置外键列为空(因为如上面提及,这种一对一是可选的,而不是必然的),这样,只有关联表方式最为适合。

本文转载自:http://blog.csdn.net/bluishglc/article/details/6021352

共有 人打赏支持
猪刚烈
粉丝 22
博文 708
码字总数 110
作品 1
海淀
程序员
18、vue-lazyload实现图片懒加载

前言:GitHub:https://github.com/Ewall1106/mall(请选择分支18) 1、安装 vue-lazyload官网:https://github.com/hilongjw/vue-lazyload 2、main.js中引入 (1)引入并注册vue-lazyload ......

Ewall_
07/24
0
0
jQuery.lazyload详解

<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script> <script src="http://file.ithome.com/js/jquery.lazyload.js"></script>   jQuery实现图片延迟加载,不知道是......

地球家园
2014/03/05
0
0
Vue + better-scroll 实现移动端字母索引导航

shortcutList 是通过计算属性得到的,取 title 的第一个字符即可。 使用 better-scroll 使用 better-scroll 实现滚动。对了,使用的时候别忘了用 import 引入。 使用 created 方法...

sinat_17775997
05/07
0
0
jquery lazyload 图片延时加载

延迟加载的特性,也有的称为惰性加载,可以最大程度避免了数据库的开销,并做到按需获取,提升了性能。系统在模型初始化的时候会创建数据库操作对象,但是这个时候并不会马上进行数据库连接,...

天外飘雪
2012/11/07
0
0
用JsonRestStore延迟加载子节点填充Dojo Tree

分享教程: jsonRest 这个store怎么放到ForestTreeModel http://www.ibm.com/developerworks/web/library/wa-lazyload/index.html?ca=drs-...

刘文豪
2011/09/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python3.6 取余运算

python中取余运算逻辑如下: 如果a 与d 是整数,d 非零,那么余数 r 满足这样的关系: a = qd + r , q 为整数,且0 ≤ |r| < |d|。 经过测试可发现,python3.6中取余运算得到的 r 是正整数;...

colinux
7分钟前
0
0
[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
3
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
3
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
1
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部