hibernate注解(三)中,我提高过一对一(@OneToOne)懒加载失效的问题。虽然给出了解决方法,但并没有给出完整的解决方案。今天我专门针对该问题进行讨论。至于懒加载失效的原因,在之前的文章中已经我已经叙述过了,就不再重复了,不明白的可以去看看。

一、测试环境

数据库:myqsl

代码:主:Student,从:Card

表:


  1. DROP TABLE IF EXISTS `student`;
  2. CREATE TABLE `student` (
  3. `ID` int(11) NOT NULL,
  4. `NAME` varchar(50) NOT NULL,
  5. `CARD_ID` int(11) DEFAULT NULL,
  6. PRIMARY KEY (`ID`),
  7. KEY `PK_CARD_ID` (`CARD_ID`),
  8. CONSTRAINT `PK_CARD_ID` FOREIGN KEY (`CARD_ID`) REFERENCES `card` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  10. DROP TABLE IF EXISTS `card`;
  11. CREATE TABLE `card` (
  12. `ID` int(11) NOT NULL,
  13. `CODE` varchar(32) NOT NULL,
  14. PRIMARY KEY (`ID`)
  15. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

代码:


  1. package com.po;
  2. import javax.persistence.CascadeType;
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.FetchType;
  6. import javax.persistence.GeneratedValue;
  7. import javax.persistence.GenerationType;
  8. import javax.persistence.Id;
  9. import javax.persistence.JoinColumn;
  10. import javax.persistence.OneToOne;
  11. import javax.persistence.Table;
  12. @Entity
  13. @Table(name = "Student")
  14. public class Student {
  15. private int id;
  16. private String name;
  17. private Card card;
  18. @Id
  19. @GeneratedValue(strategy = GenerationType.IDENTITY)
  20. @Column(name = "ID", unique = true, nullable = false)
  21. public int getId() {
  22. return id;
  23. }
  24. public void setId(int id) {
  25. this.id = id;
  26. }
  27. @Column(name = "NAME", nullable = false, length = 50)
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  35. @JoinColumn(name = "CARD_ID")
  36. public Card getCard() {
  37. return card;
  38. }
  39. public void setCard(Card card) {
  40. this.card = card;
  41. }
  42. }

  1. package com.po;
  2. import javax.persistence.CascadeType;
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.FetchType;
  6. import javax.persistence.GeneratedValue;
  7. import javax.persistence.GenerationType;
  8. import javax.persistence.Id;
  9. import javax.persistence.OneToOne;
  10. import javax.persistence.Table;
  11. @Entity
  12. @Table(name = "card")
  13. public class Card {
  14. private int id;
  15. private String code;
  16. private Student student;
  17. @Id
  18. @GeneratedValue(strategy = GenerationType.IDENTITY)
  19. @Column(name = "ID", unique = true, nullable = false)
  20. public int getId() {
  21. return id;
  22. }
  23. public void setId(int id) {
  24. this.id = id;
  25. }
  26. @Column(name = "CODE", length = 32, nullable = false)
  27. public String getCode() {
  28. return code;
  29. }
  30. public void setCode(String code) {
  31. this.code = code;
  32. }
  33. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "card")
  34. public Student getStudent() {
  35. return student;
  36. }
  37. public void setStudent(Student student) {
  38. this.student = student;
  39. }
  40. }

方案一

在card表增加一个student表的外键字段STUDENT_ID,并在Card类的@OneToOne下增加@JoinColumn(name = "STUDENT_ID"),去掉mappedBy = "card",即


  1. DROP TABLE IF EXISTS `card`;
  2. CREATE TABLE `card` (
  3. `ID` int(11) NOT NULL,
  4. `CODE` varchar(32) NOT NULL,
  5. `STUDENT_ID` int(11) DEFAULT NULL,
  6. PRIMARY KEY (`ID`),
  7. KEY `PK_STUDENT_ID` (`STUDENT_ID`),
  8. CONSTRAINT `PK_STUDENT_ID` FOREIGN KEY (`STUDENT_ID`) REFERENCES `student` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  1. public class Card {
  2. // ... 略
  3. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  4. @JoinColumn(name = "STUDENT_ID")
  5. public Student getStudent() {
  6. return student;
  7. }
  8. // ... 略
  9. }

优点:不改变Student与Card在代码中的对应关系(一对一)

缺点:需要同时维护Student和Card的两个外键。

方案二

改为主键关联。


  1. DROP TABLE IF EXISTS `student`;
  2. CREATE TABLE `student` (
  3. `ID` int(11) NOT NULL,
  4. `NAME` varchar(50) NOT NULL,
  5. PRIMARY KEY (`ID`),
  6. CONSTRAINT `PK_CARD_ID` FOREIGN KEY (`ID`) REFERENCES `card` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  1. public class Student {
  2. // ... 略
  3. @Id
  4. @GenericGenerator(name = "PK_Card", strategy = "foreign", parameters = @Parameter(name = "property", value = "card"))
  5. @GeneratedValue(generator = "PK_Card")
  6. @Column(name = "ID", unique = true, nullable = false)
  7. public int getId() {
  8. return id;
  9. }
  10. // ... 略
  11. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
  12. @PrimaryKeyJoinColumn
  13. public Card getCard() {
  14. return card;
  15. }
  16. // ... 略
  17. }

  1. public class Card {
  2. // ... 略
  3. @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "card", optional = false)
  4. public Student getStudent() {
  5. return student;
  6. }
  7. // ... 略
  8. }

除了改变student表的主键、外键结构外,Student类和Card类也要做相应修改,尤其注意“optional”,要设置为false,否则无法实现懒加载。

优点:不改变Student与Card在代码中的对应关系(一对一)

缺点:改动较大,且使用主键关联具有局限性。

PS:主键关联的局限性

使用主键关联会影响数据存储结构,主键关联是一种强耦合,以上述为例:Card存在时,Student才能存在,Card消亡时,Student也随之消失。这是因为Student的主键依赖于Card主键,Student无法独立存在(就是说必须先有学生卡,才能有学生)。

方案三

将Card类中的OneToOne改为OneToMany(一对多)。


  1. public class Card {
  2. private Set students;
  3. // ... 略
  4. @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "card")
  5. public Set<Student> getStudents() {
  6. return students;
  7. }
  8. public void setStudents(Set students) {
  9. this.students = students;
  10. }
  11. // ... 略
  12. }

优点:数据库不用修改

缺点:需要修改Student与Card在代码中的对应关系

方案四

放弃用注解的方式,改为Xml方式来实现hibernate模型设计,并在Card Xml的OneToOne标签中添加constrained属性,靠注解解决的办法已经没有了(instrument增强就算了吧,很麻烦)。

最后,我们来评估下以上方案的可行性。

方案一:从可读性来讲,是最容易理解的,但需要维护两个外键,如果程序控制不好的话,容易出问题,即关联错误。

方案二:主键关联虽然有些约束,但也取决于业务需求,比如订单和订单详情,采用主键关联也挺合适的,只是不适合相对灵活的对象关系。

方案三:改动在我看来是最小的了,牺牲了一定的可读性(关系从Card角度看变为了一对多),我个人比较喜欢该种方案,因此推荐。

方案四:如果不采用注解,而采用Xml的话,我是很推荐这种方案的,注解虽然优点多,也趋于主流,但最传统的Xml,功能还是最强大的。但如果你仅为了解决该问题,而将注解和Xml混合使用的话,我建议你还是放弃吧。

原文地址:https://blog.csdn.net/wangpeng047/article/details/19624795

Hibernate @OneToOne懒加载实现解决方案的更多相关文章

  1. hibernate的懒加载问题

    产生原因: 当使用hibernate查询一个对象的时候,如果Session关闭,再调用该对象关联的集合或者对象的时候,会产生懒加载异常! 解决方案: 方案一: 在Session关闭之前,查询对象关联的 ...

  2. Android中ViewPager+Fragment取消(禁止)预加载延迟加载(懒加载)问题解决方案

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53205878本文出自[DylanAndroid的博客] Android中Vie ...

  3. Hibernate的懒加载session丢失解决方法

    在web.xml加入spring提供的过滤器,延长session的生命周期 <!--Hibernate的懒加载session丢失解决方法 --> <filter> <fi ...

  4. webpack多页面开发与懒加载hash解决方案

    之前讨论了webpack的hash与chunkhash的区别以及各自的应用场景,如果是常规单页面应用的话,上篇文章提供的方案是没有问题的.但是前端项目复杂多变,应对复杂多页面项目时,我们不得不继续踩w ...

  5. Spring Boot JPA Entity Jackson序列化触发懒加载的解决方案

    Spring Jpa这项技术在Spring 开发中经常用到. 今天在做项目用到了Entity的关联懒加载,但是在返回Json的时候,不管关联数据有没有被加载,都会触发数据序列化,而如果关联关系没有被加 ...

  6. hibernate的懒加载

    WHY? WHAT? HOW? 所谓懒加载(lazy)就是延时加载,延迟加载.即不是不加载,而是在需要的时候才加载. 什么时候用懒加载呢,我只能回答要用懒加载的时候就用懒加载. 至于为什么要用懒加载呢 ...

  7. hibernate+spring mvc, 解决hibernate 对象懒加载 json序列化问题

    引用地址 在使用Spring MVC时,@ResponseBody 注解的方法返回一个有懒加载对象的时候出现了异常,以登录为例: @RequestMapping("login") ...

  8. hibernate+spring mvc,解决hibernate对象懒加载,json序列化失败

    在使用spring MVC时,@ResponseBody 注解的方法返回一个有懒加载对象的时候出现了异常,以登录为例: @RequestMapping("login") @Resp ...

  9. 过滤器解决hibernate中懒加载问题

    使用过滤器解决懒加载问题需要我们对过滤器的生命周期有深刻的理解 1.浏览器发送一个请求 2.请求通过过滤器执行dofilter之前的代码 3.浏览器通过过滤器到达Servlet(注意我们这里的serv ...

随机推荐

  1. 学习JDK1.8集合源码之--ArrayList

    参考文档: https://cloud.tencent.com/developer/article/1145014 https://segmentfault.com/a/119000001857894 ...

  2. PHP队列类

    /** * Created by PhpStorm. * User: LAMP-Q哥 * Date: 2017/8/3 * Time: 12:58 */ class Queue { private $ ...

  3. 会话技术之cookie(记录当前时间、浏览记录的记录和清除)

    cookie 会话技术: 当用户打开浏览器的时候,访问不同的资源,直到用户将浏览器关闭,可以认为这是一次会话. 作用: 因为http协议是一个无状态的协议,它不会记录上一次访问的内容.用户在访问过程中 ...

  4. 视觉暂留-Info:这些神奇的“视觉暂留”动画,每一幅都让人拍案叫绝!

    ylbtech-视觉暂留-Info:这些神奇的“视觉暂留”动画,每一幅都让人拍案叫绝! 1.返回顶部 1. 这些神奇的“视觉暂留”动画,每一幅都让人拍案叫绝! 原创|发布:2018-05-28 19: ...

  5. python基础总结篇

    ''' 数据类型 数值 int: 字符串转int,只能转纯数字组成的字符串 小数,去掉小数部分 bool,true 1 false 0 float: 字符串转float,要么是纯数字的字符串,要么是纯 ...

  6. typroa 和markdown基操

    目录 标题 一级标题 二级标题 字体 图片 来插入图片,如在同意文件夹上,可直接加图片名 数学公式 编辑表格 标题 一级标题 二级标题 三级标题 无序标题 *加空格,无序标题 也可以使用ctrl = ...

  7. Directx11教程(20) 一个简单的水面

    原文:Directx11教程(20) 一个简单的水面 nnd,以前发的这篇教程怎么没有了?是我自己误删除了,还是被系统删除了? 找不到存稿了,没有心情再写一遍了.      简单说一下,本篇教程就是实 ...

  8. 在MaxCompute中配置Policy策略遇到结果不一致的问题

    背景信息: 本文以如下场景为基准进行编写,如下: 用户通过DataWorks-简单模式使用MaxCompute: 用户具有DataWorks默认角色,如DataWorks开发者角色: 用户通过cons ...

  9. PHP实现打印出库单,有没有实现过?

    https://mp.weixin.qq.com/s/X3JldplICRq7KR0HNFcpuw 背景 有时候你在实现一个出库订单之类的功能模块,这里也有可能要你的站点也实现相应的打印出库单预览,今 ...

  10. Java练习 SDUT-3106_小鑫数数儿

    小鑫数数儿 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 某天小鑫忽然得到了许多的数字,他很好学,老师给他布置了一个任 ...