JPA定义实体之间的关系有如下几种:
@OneToOne
@ManyToOne
@OneToMany
@ManyToMany
在定义它们的时候可以通过fetch属性指定加载方式,有两个值:
FetchType.LAZY:延迟加载
FetchType.EAGER:急加载
急加载就好理解了,在加载一个实体的时候,其中定义是急加载的的属性(property)和字段(field)会立即从数据库中加载
开发过程中遇到问题最多的就是延迟加载,并且问题都是一个:
“为什么我定义为延迟加载了,但没起作用,相关的属性或者字段还是会立即加载出来?”
对于这个问题,我的理解是这样的,我们首先假设有如下的影射关系:
@Entity
@Table(name = "orders")
class Order{

@OneToMany(cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},fetch = FetchType.LAZY,mappedBy = "order")
private Collection
lineItems = new HashSet
();

@OneToOne(cascade={CascadeType.REMOVE},fetch=FetchType.LAZY,mappedBy="order")
@JoinColumn(name="order_id")
private OrderPrice salePrice;

@OneToOne(cascade={CascadeType.REMOVE},fetch=FetchType.LAZY)
@JoinColumn(name="customer_id")
private Customer customer;
}

@Entity
@Table(name = "order_items")
class LineItem{

@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH},fetch = FetchType.LAZY)
@JoinColumn(name = "order_id",referencedColumnName = "order_id")
private Order order;

}

@Entity
@Table(name = "order_finance")
@AttributeOverride(name="id",column=@Column(name="order_id"))
class OrderPrice extends Price{

private Order order;

@OneToOne(cascade={},fetch=FetchType.LAZY)
@JoinColumn(name="order_id",referencedColumnName="order_id")
public Order getOrder() {
return order;
}

public void setOrder(Order order) {
this.order = order;
}

}

@MappedSupperclass
@Table(name = "order_finance")
class Price{
@Id
public Integer getId(){
...
}
}
表的关系是:orders表是一个单独的表,order_items表有一个外键(order_id)引用到orders 表,order_finance有一个外键(order_id)引用到orders表.
order_items——->orders<————order_finance

customer
现在的问题就是:
Order.lineItems 这个@OneToMany的LAZY延迟加载是起作用的,find order的时候没有find出lineItems
Order.customer 这个@OneToMany的LAZY延迟加载是起作用的,find order的时候没有find出Customer
Order.salePrice 这个@OneToOne的LAZY延迟加载没起作用,find order后会把相关的OrderPrice也fetch 出来
LineItem.order 这个@ManyToOne的LAZY延迟加载是起作用的,find lineitem没有把相关的order find出来
OrderPrice.order 这个@OneToOne的LAZY延迟加载没起作用,find orderprice的时候把相关的order find出来了
延迟加载,顾名思义,就是在访问具体的属性时才从数据库中加载,比如例子中,只有调用OrderPrice.getOrder()的时候才应该会 加载Order这个实体,加载OrderPrice的时候是不应该加载Order的。
那么首先想想,对于延迟加载,hibernate怎么知道什么时候会调用到相关的实体的get方法呢?
答案是它不知道,hibernate不知道什么时候会调用到相关的get方法,那么hibernate如何实现只有访问到才加载这一点?
hibernate 使用了代理(Proxy),对实体的调用会被代理接受和处理,hibernate可以设置这个代理被调用到的时候去加载数据, 从而实现延迟加载。那么对于一个映射对象,要么它有值,要么它是null,对于null值建立代理是没多大作用的,而且也不能对null建立动态代理。那 就是说hibernate在对延迟加载建立代理的时候要考虑这个映射的对象是否是null。如果是null不需要建立代理,直接把映射的值设置成 null,如果映射的对象不为null,那么hibernate就建立代理对象
延迟加载失败都是由于确定映射的内容是否是null引起的
先 来看@OneToMany,比如例子中的Order.lineitems,这是一个Collection,hibernate在加载Order 的时候不加载lineitems,而是创建一个代理(Proxy)一个针对Collection的代理(通常是 org.hibernate.collection.persistentBag)。除非你调用了像Order.getLineItems.size() 或者Order.getLineItems.get()方法的时候hibernate才会去加载这个order的lineitems数据,要不然只是调用 Order.getLineItems是不会加载到数据的,因为这个时候并没有具体的访问LineItem.
由于代理是针对Collection建立的,而不是针对实体建立的,hibernate不用太多考虑是否为null,如果lineitem没有, 也只是代表这个集合是长度是0,这个集合是不为Null的。所以这很容易实现延迟加载
现在在来看例子@OneToOne Order.salePrice。它为什么会失败呢?
hibernate 也会建立代理,但这个代理是针对OrderPrice建立的(如果延迟加载成功,这个代理类形如 Customer_javasisst_$1),默认optioanl=true,也就是说OrderPrice可以为null,那么hibernate 就要考虑,这里是放一个null呢?还是放一个代理。但在Order这个实体里是不能确定它有没有价格的(但在价格里知道他的Order,有个外键指向 order),所以hibernate要确认这个OrderPrice是否存在,这个确认就导致的延迟加载失败,因为OrderPrice要被查询一次, 如果不存在映射值为null,如果存在这个时候值都取出来了,当然就不用什么代理了
Order.customer延迟加载是成功的,order表有一个外键关联到customer表,hibernate应该从这里知道这个 customer是确实存在的,不用把映射值设置成null了,可以设置成代理类Customer_javasisst_$2
那如果把Order.salePrice的映射定义修改成:
@OneToOne(cascade={CascadeType.REMOVE},fetch=FetchType.LAZY,optional=false,mappedBy=”order”)
@JoinColumn(name=”order_id”)
private OrderPrice salePrice;
延迟加载就成功了,因为optional=false指定salePrice不是可选的,必须有值,所以hibernate也不用考虑是该放 null还是放代理,既然必须有值,又是延迟加载,那就设置成代理类了
根据上面所说的,OrderPrice定义有一个外键关联到Order,那OrderPrice.order这个延迟加载应该是成功的,但为什么 会失败呢?
难道是Order与OrderPrice两边都定义了OneToOne关系?
我这个例子中,这里失败我想是因为OrderPrice这个实体的定 义:@AttributeOverride(name=”id”,column=@Column(name=”order_id”))
再来看看ManyToOne的LineItem.order,这个延迟加载也是成功的。因为lineitem定义了外健关系到order
对于延迟加载的对象,如果已经脱离了容器,调用会得到org.hibernate.LazyInitializationException: could not initialize proxy – no Session方法异常
还有一种情况下延迟加载“看起来是没起作用的”:其实是起作用的,但可能在什么地方的代码调用到了相关的get方法,把延迟加载的对象加载出来 的,所以看起来是没有成功的
总结:
对于延迟加载,hibernate无法知道什么时候会调用到延迟加载的属性/字段的get方法,所以对于延迟加载的属性/字 段,hibernate会通过建立代理Proxy来包装(Wrapper)一下
代 理可能会根据实体本身建立,也可以是根据一个集合建立,如果是根据一个集合建立,延迟加载一般都能成功,如果是根据实体建立,null是不能建 立代理的,如果能够确定代理类一定存在,那延迟加载就能成功,相关的映射放置的是代理类,如果不能确定映射的属性是否存在,那就会去数据库中进行查询,这 就导致的延迟失败。
外键定义可以让hibernate知道映射的属性是否存在
也可以通过optional=false来告诉hibernate,映射的属性一定存在

转载于:https://www.cnblogs.com/navyhj/p/5582465.html

hibernate FetchType理解相关推荐

  1. Hibernate flush理解

    问题 在spring框架没有事务的情况下,通过hibernate的session.save(entity),无法将数据持久化至数据库中,即使强制刷新后(flush())后也同样如此. 原因 混淆了sp ...

  2. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(1):Mybatis和Hibernate概念理解...

    一.关键字说明: oop:面向对象 aop:面向切面 ioc:控制反转 orm:对象关系映射 pojo:数据库表映射的java实体类 二.常识说明: 1.hibernate和mybatis都属于持久层 ...

  3. 面试题:谈谈你对hibernate的理解

    说说这类问题一般要和一个东西比較.说说他们的长处和缺点,hibernate就和JDBC比較呗.你就说说JDBC的优缺点.然后说说hibernate的优缺点,最后对照得出hibernate更好. hib ...

  4. 关于Struts+Spring+Hibernate的理解

    Struts,Spring和Hibernate是目前企业最流行的组合框架.一般一个Web项目分为四层:呈现层, 业务逻辑层. 持久层和数据库层.Struts负责呈现层...... 转载于:https: ...

  5. hibernate缓存理解

    为什么80%的码农都做不了架构师?>>> 1)Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数!  只在session范围有效 ...

  6. hibernate 复合主键 根据主键删除_6道常见的 Hibernate 面试题

    1.Hibernate的理解 Java的核心之一是面向对象设计,那么如何把数据库的数据封装成一个对象返回呢?如何把一个对象出局后保存到数据库呢?Java采用了jdbc来解决这个问题,但是数据量如何解决 ...

  7. struts、hibernate、spring、 mybatis、 spring boot 等面试题汇总

    1.谈谈你对Struts的理解. 答: 1. struts是一个按MVC模式设计的Web层框架,其实它就是一个大大的servlet,这个Servlet名为ActionServlet,或是ActionS ...

  8. FW: How to use Hibernate Lazy Fetch and Eager Fetch Type – Spring Boot + MySQL

    原帖 https://grokonez.com/hibernate/use-hibernate-lazy-fetch-eager-fetch-type-spring-boot-mysql In the ...

  9. Hibernate框架ORM的实现原理-不是技术的技术

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴!  Hib ...

  10. hibernate中的dialect解释

    dialect就是"方言",因为hibernate是要把Java对象转换成关系数据库来描述的,而关系数据库虽然有一些统一的标准,如SQL-92等,但是实际上各数据库如Oracle, ...

最新文章

  1. crontab修改默认编辑器
  2. LeetCode.3-最长无重复字符子串(Longest Substring Without Repeating Characters)
  3. Apache Spark 技术团队开源机器学习平台 MLflow
  4. 【计算机网络】第五章 数据链路层(3)
  5. 从流水中倒推算出销量为多某值的日期
  6. 前端学习(706):do-while案例
  7. 电脑太慢了最简单的办法怎么弄_电脑感染病毒的10种症状及简单处理办法 电脑中病毒的症状介绍...
  8. win11搜索位置在哪 Windows11搜索位置的设置方法
  9. POJ1007 UVA612 UVALive5414 ZOJ1188 HDU1379 Bailian4086 DNA Sorting【排序+逆序数】
  10. Win10下Pytorch的安装和使用[斗之力三段]
  11. STL-vector容器
  12. cacti监控mysql
  13. 获取单个数据库的邮箱数量
  14. css里给文字加下划线代码,css给文字加下划线
  15. CentOS5u11 Oracle 10g 生产RMAN备份可用性恢复测试
  16. BZOJ 1695 [Usaco2007 Demo]Walk the Talk 链表+数学
  17. ArtWork+并查集二维
  18. 概念:伪随机数、种子以及C中的随机函数
  19. numpy 矩阵求和小技巧
  20. 苹果手机浏览器 不支持line-height属性的解决方法

热门文章

  1. 前端实现用户自定义建表_Excel、SQL、Python分别实现行列转换
  2. 基于SSM的MSDN资源发布网站
  3. react刷新页面_【跟着官网学React】Hello World
  4. html基础之弹性布局(dispaly :flex)
  5. k8s/docker 安装yapi和MongoDB
  6. IntelliJ IDEA创建和配置Maven项目并运行
  7. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_14-页面静态化-数据模型-远程请求接口...
  8. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_09-webpack研究-webpack介绍
  9. 针对利用tzselect修改时间及ln -sf 修改系统时间不好使的情况 linux 6.5
  10. Ubuntu 18.04 root 使用ssh密钥远程登陆