`
为了明天
  • 浏览: 115017 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hibernate FetchType

阅读更多
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,映射的属性一定存在
分享到:
评论

相关推荐

    hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法

    hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法 Hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法是 Hibernate 框架中的一种常见问题。当我们在 Hibernate 中使用懒加载特性时,可能会遇到 ...

    hibernate一对多项目

    若希望在获取父实体时同时加载子实体,可以设置`fetch = FetchType.EAGER`。 6. **缓存策略**: - Hibernate提供了一级缓存(Session级别)和二级缓存(SessionFactory级别)。合理设置缓存策略可以提高数据读取...

    HibernateDemo(hibernate基本用法演示)

    9. **延迟加载(Lazy Loading)**:通过 `@OneToMany(mappedBy = "..." fetch = FetchType.LAZY)` 可以实现懒加载,只有在真正需要时才会加载关联的对象,避免了数据冗余。 10. **事件监听**:可以注册事件监听器,...

    hibernate所需驱动

    10. ** CascadeType 和 FetchType**:在映射文件中,可以设置Cascade属性来决定操作一个实体时是否级联到关联实体,FetchType则决定了关联数据是在需要时懒加载还是立即加载。 通过理解并熟练应用这些知识点,...

    Hibernate5实例程序

    通过`@LazyCollection(LazyCollectionOption.EXTRA)`或`@OneToMany(mappedBy = "property", fetch = FetchType.LAZY)`等注解实现懒加载,以提高程序性能,只在真正需要时加载关联数据。 12. **事件监听(Event ...

    Hibernate PDf

    - **减少N+1问题**:通过FetchType.EAGER或FetchType.LAZY等方式来避免查询效率低下。 - **异常处理**:正确处理Hibernate抛出的各种异常,比如`org.hibernate.NonUniqueObjectException`等,确保程序健壮性。 - **...

    hibernate入门简单实例

    13. **懒加载(Lazy Loading)**:Hibernate支持懒加载机制,即关联的对象在需要时才从数据库加载,这通过`@OneToMany`, `@ManyToOne`, `@OneToOne`等注解的`fetch = FetchType.LAZY`实现。 14. **缓存(Caching)*...

    hibernate小白极简实例

    `@OneToMany`, `@ManyToOne`, `@OneToOne`等注解可以定义关联关系,`fetch=FetchType.LAZY`启用懒加载。级联操作(`cascade=CascadeType.ALL`)使得对父对象的操作自动影响子对象。 10. **实体关系映射(E-R ...

    Hibernate 项目图片资料

    `@OneToMany(fetch = FetchType.LAZY)`实现懒加载。 10. **缓存机制** Hibernate提供了一级缓存(Session级别的内存缓存)和二级缓存(SessionFactory级别的分布式缓存),减少数据库访问,提高系统性能。 11. **...

    HibernateAnnotations 中文版

    1. **延迟加载(Lazy Loading)**: 使用 `@OneToMany` 和 `@ManyToOne` 注解时,可以通过 `fetch = FetchType.LAZY` 实现关联对象的懒加载,降低初始化时的内存消耗。 2. **批处理(Batch Processing)**: 通过设置 ...

    hibernate基础教程.pdf

    使用 `@ManyToOne`, `@OneToMany`, `@OneToOne`, `@ManyToMany` 等注解可以定义对象间的关联关系,并通过 `fetchType.LAZY` 实现懒加载。级联操作则允许我们在操作一个对象时,自动处理与其关联的对象集合,如 `...

    Hibernate API Documentation 3.3.0.SP1

    1. Lazy Loading:延迟加载是一种节省内存的技术,只有在需要访问关联对象时才会加载,通过@OneToMany(mappedBy = "...", fetch = FetchType.LAZY)实现。 2. Batch Size:批量操作可以提高性能,例如设置批处理大小...

    Hibernate 中文文档

    **Hibernate 框架概述** Hibernate 是一个开源的对象关系映射(ORM)框架,它允许开发者将Java对象与关系数据库中的表进行映射,从而在Java应用中处理数据时,可以像操作对象一样操作数据库。这极大地简化了数据库...

    hibernate-distribution-3.6.10.Final-dist

    12. **懒加载(Lazy Loading)与立即加载(Eager Loading)**:通过`@ManyToOne(fetch = FetchType.LAZY)`等设置,控制关联对象的加载时机,优化性能。 总的来说,Hibernate 3.6.10 Final是企业级Java应用中不可或...

    hibernate中处理大字段 网上收集的文档

    在Java的持久化框架Hibernate中,处理大数据字段,如文本、图像或者其他大量数据,通常涉及到CLOB(Character Large Object)和BLOB(Binary Large Object)类型。这些类型用于存储数据库中的大文本或二进制数据。...

    学习hibernate第二天

    若希望关联对象在加载主对象时一并加载,可以使用`fetch = FetchType.EAGER`。 3. **外键维护**:在双向关联中,通常只有一方负责维护外键,这里由UserProfile负责,因此在修改User对象的UserProfile时,应通过User...

    hibernate的lazy策略forClass

    在Java的持久化框架Hibernate中,懒加载(Lazy Loading)是一种重要的对象关系映射策略,用于提高应用程序的性能。懒加载的基本思想是延迟加载,即当真正需要数据时,才去数据库加载。在这个场景中,我们关注的是...

    hibernate的知识总结

    - **Hibernate生成策略**:可以通过注解`@Basic`来声明属性的存取策略,例如延迟获取(`FetchType.LAZY`)或即时获取(`FetchType.EAGER`)。 - **时间精度映射**:通过`@Temporal`注解定义映射到数据库的时间精度,...

    hibernate实体系注解

    在Java世界中,Hibernate是一个非常流行的ORM(对象关系映射)框架,它允许开发者使用面向对象的方式来操作数据库,极大地简化了数据库操作。本教程将深入探讨如何在Hibernate中使用注解来实现实体类的配置,特别是...

    hibernate v3.04中文参考手册

    - 适当使用FetchType.LAZY和EAGER,控制关联对象的加载时机。 通过深入学习和实践Hibernate V3.04中文参考手册,开发者能熟练掌握ORM技术,提高Java应用的数据访问效率,同时理解面向对象与关系数据库之间的桥梁,...

Global site tag (gtag.js) - Google Analytics