文档章节

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

猪刚烈
 猪刚烈
发布于 2014/10/12 11:41
字数 1754
阅读 21
收藏 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
海淀
程序员
jquery lazy load

LazyLoad是一个Js编写的Jq插件,它可以延迟加载页面中的图片,在浏览器可视范围中的图片会被加载。 如何使用:LazyLoad依赖于Jquery,在html的结尾处 ,就是在前。 你必须改变图片的标签,图片的...

张子浩
08/20
0
0
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
前端性能优化之按需加载(React-router+webpack)

一、什么是按需加载 和异步加载script的目的一样(异步加载script的方法),按需加载/代码切割也可以解决首屏加载的速度。 什么时候需要按需加载 如果是大文件,使用按需加载就十分合适。比如一个...

大灰狼的小绵羊哥哥
08/28
0
0
Vue + better-scroll 实现移动端字母索引导航

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

sinat_17775997
05/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

腾讯投资最高1.75亿美元正式进军菲律宾移动支付市场

菲律宾长途电话公司(PLDT)公司今日宣布,中国互联网巨头腾讯和私募股权公司KKR将获得该公司旗下金融科技公司Voyager Innovations的少数股权。 PLDT在一份声明中称:“腾讯和KKR最多将分别收...

linuxCool
18分钟前
1
0
正则介绍及grep/egrep用法

10月16日任务 9.1 正则介绍_grep上 9.2 grep中 9.3 grep下 扩展 把一个目录下,过滤所有*.php文档中含有eval的行 grep -r --include="*.php" 'eval' /data 正则介绍 正则就是一串有规律的字符...

hhpuppy
29分钟前
0
0
J2Cache 中使用 Lettuce 替代 Jedis 管理 Redis 连接

一直以来 J2Cache 都是使用 Jedis 连接 Redis 服务的。Jedis 是一个很老牌的 Redis 的 Java 开发包,使用很稳定,作者维护很勤勉,社区上能搜到的文章也非常非常多。算是使用范围最广的 Redi...

红薯
今天
11
0
一个可能的NEO链上安全随机数解决方案

0x00 困境 链上安全随机数生成应该算是一个比较蛋疼的问题,哪怕你的系统再牛逼,合约程序困在小小的虚拟机里,哪怕天大的本事也施展不开。 更悲催的是,交易执行的时候,是在每一个节点都执...

暖冰
今天
1
0
【大福利】极客时间专栏返现二维码大汇总

我已经购买了如下专栏,大家通过我的二维码你可以获得一定额度的返现! 然后,再给大家来个福利,只要你通过我的二维码购买,并且关注了【飞鱼说编程】公众号,可以加我微信或者私聊我,我再...

飞鱼说编程
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部