文档章节

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

猪刚烈
 猪刚烈
发布于 2014/10/12 11:41
字数 1754
阅读 20
收藏 0
点赞 0
评论 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
海淀
程序员
Vue + better-scroll 实现移动端字母索引导航

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

sinat_17775997 ⋅ 05/07 ⋅ 0

yadong.zhang/DBlog

DBlog简介 DBlog是一款简洁美观、自适应的Java博客系统。使用springboot开发,前端使用Bootstrap。支持移动端自适应,配有完备的前台和后台管理功能。 网站预览 https://www.zhyd.me 写在前面...

yadong.zhang ⋅ 04/23 ⋅ 0

React 16 加载性能优化指南

React 16 加载性能优化指南 ,document.getElementById('root')); var path = require('path'); // 读取写好的 loading 态的 html 和 cssvar loading = { } var webpackConfig = {entry: 'in......

Starkwang ⋅ 05/22 ⋅ 0

前端安全大起底 | JTalk 掘金线下活动第八期

🙋 报名 扫码报名: 报名链接:点我报名 🚀 介绍 JTalk 团队专场来了! 掘金线下活动 JTalk 由掘金主办,每期 JTalk 会邀请垂直行业的优秀工程师来分享优秀的实践经验,技巧方法。旨在为...

膜法小编 ⋅ 05/27 ⋅ 0

阿里云Apsara Block Storage企业级分布式块存储产品

摘要: Apsara Block Storage是阿里云推出的一款企业级分布式块存储产品,帮助企业市场头部客户构建高性能、弹性、可靠的大规模横向扩展云存储服务平台。可对接各种类型计算平台,包括阿里云...

阿里云云栖社区 ⋅ 前天 ⋅ 0

Apsara Block Storage技术解读

Apsara Block Storage横空出世 什么是Apsara Block Storage? Apsara Block Storage是阿里云推出的一款企业级分布式块存储产品,帮助企业市场头部客户构建高性能、弹性、可靠的大规模横向扩展...

孟蓁蓁 ⋅ 06/12 ⋅ 0

阿里云Apsara Block Storage企业级分布式块存储产品发布

摘要: Apsara Block Storage是阿里云推出的一款企业级分布式块存储产品,帮助企业市场头部客户构建高性能、弹性、可靠的大规模横向扩展云存储服务平台。可对接各种类型计算平台,包括阿里云...

猫耳m ⋅ 前天 ⋅ 0

移动端本地 H5 秒开方案探索与实现

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 企业微信移动端项目中有需求要展示数据趋势的可视化图表,经过调研,最终决定以单页面 H5 来完成,对 APP 里的一些使用 H5 实现的...

腾讯云加社区 ⋅ 06/11 ⋅ 0

ORM数据访问组件--ELinq

ELinq 是一个轻量简单易用的开源Linq ORM数据访问组件,支持Nullable类型和枚举类型,对Linq的谓词提供了完美的支持,旨在让绝大部份的主流数据库都使用 Linq 来进行程序开发,让开发人员访问...

netcasewqs ⋅ 2012/12/17 ⋅ 2

MyBatis 之 延迟加载(Lazy Load)

LazyLoad 的作用: 在数据与对象进行 mapping 操作时,只有在真正使用到 该对象时,才进行 mapping 操作,以减少数据库查询开销,从而提升系统性能。 但是Lazy Load也有缺点,在 按需加载时会...

pradosoul ⋅ 2015/09/17 ⋅ 2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

NFS介绍 NFS服务端安装配置 NFS配置选项

NFS介绍 NFS是Network File System的缩写;这个文件系统是基于网路层面,通过网络层面实现数据同步 NFS最早由Sun公司开发,分2,3,4三个版本,2和3由Sun起草开发,4.0开始Netapp公司参与并主导...

lyy549745 ⋅ 12分钟前 ⋅ 0

Spring AOP 源码分析 - 筛选合适的通知器

1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出合适的通知器(Advisor...

java高级架构牛人 ⋅ 35分钟前 ⋅ 0

HTML-标签手册

标签 描述 <!--...--> 定义注释。 <!DOCTYPE> 定义文档类型。 <a> 定义锚。超链接 <abbr> 定义缩写。 <acronym> 定义只取首字母的缩写。 <address> 定义文档作者或拥有者的联系信息。 <apple......

ZHAO_JH ⋅ 36分钟前 ⋅ 0

SylixOS在t_main中使用硬浮点方法

问题描述 在某些使用场景中,应用程序不使用动态加载的方式执行,而是跟随BSP在 t_main 线程中启动,此时应用代码是跟随 BSP 进行编译的。由于 BSP 默认使用软浮点,所以会导致应用代码中的浮...

zhywxyy ⋅ 44分钟前 ⋅ 0

JsBridge原理分析

看了这个Github代码 https://github.com/lzyzsd/JsBridge,想起N年前比较火的Hybrid方案,想看看现在跨平台调用实现有什么新的实现方式。代码看下来之后发现确实有点独特之处,这里先把核心的...

Kingguary ⋅ 56分钟前 ⋅ 0

Intellij IDEA神器常用技巧五-真正常用快捷键(收藏级)

如果你觉得前面几篇博文太啰嗦,下面是博主多年使用Intellij IDEA真正常用快捷键,建议收藏!!! sout,System.out.println()快捷键 fori,for循环快捷键 psvm,main方法快捷键 Alt+Home,导...

Mkeeper ⋅ 56分钟前 ⋅ 0

Java 静态代码分析工具简要分析与使用

本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能、特性等方面对它们进行分析和比较,...

Oo若离oO ⋅ 58分钟前 ⋅ 0

SpringBoot自动配置小记

spring-boot项目的特色就在于它的自动配置,自动配置就是开箱即用的本源。 不过支持一个子项目的自动配置,往往比较复杂,无论是sping自己的项目,还是第三方的,都是如此。刚接触会有点乱乱...

大_于 ⋅ 今天 ⋅ 0

React jsx 中写更优雅、直观的条件运算符

在这篇文字中我学到了很多知识,同时结合工作中的一些经验也在思考一些东西。比如条件运算符 Conditional Operator condition ? expr_if_true : expr_if_false 在jsx中书写条件语句我们经常都...

开源中国最帅没有之一 ⋅ 今天 ⋅ 0

vim编辑模式与命令模式

5.5 进入编辑模式 从编辑模式返回一般模式“Esc” 5.6 vim命令模式 命令 :“nohl”=no high light 无高亮,取消内容中高亮标记 "x":保存退出,和wq的区别是,当进入一个文件未进行编辑时,使...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部