Hibernate:为啥 FetchType.LAZY 注释的集合属性急切地加载?

Posted

技术标签:

【中文标题】Hibernate:为啥 FetchType.LAZY 注释的集合属性急切地加载?【英文标题】:Hibernate : Why FetchType.LAZY-annotated collection property eagerly loading?Hibernate:为什么 FetchType.LAZY 注释的集合属性急切地加载? 【发布时间】:2017-03-19 03:56:05 【问题描述】:

我尝试实现简单的one-to-many 关联。在使用调试模式检查项目对象后,我发现 List<Bid> bids 已经加载。但是List<Bid>bids 属性用FetchType.LAZY 注释。一些书籍和网页声称FetchType.LAZY 是 JPA 提供者接受或拒绝的暗示。但我想知道 JPA 提供商在什么情况下会忽略 FetchType.LAZY。提前谢谢你。

@Entity
@Table(name = "ITEM")
public class Item implements Serializable 

    @Id
    private Long id = null;

    private String name;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "SELLER_ID", nullable = false)
    private User seller;

    @OneToMany(mappedBy = "item", fetch = FetchType.LAZY)
    private List<Bid> bids;

    /**
     * No-arg constructor for JavaBean tools.
     */
    public Item() 

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public User getSeller() 
        return seller;
    

    public void setSeller(User seller) 
        this.seller = seller;
    

    @Override
    public String toString() 
        return "Item" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", seller=" + seller +
                ", bids=" + bids +
                '';
    

@Entity
@Table(name = "BID")
public class Bid implements Serializable 

    @Id @GeneratedValue
    @Column(name = "BID_ID")
    private Long id = null;

    @ManyToOne
    @JoinColumn(name = "ITEM_ID", nullable = false, updatable = false, insertable = false)
    private Item item;

    @ManyToOne
    @JoinColumn(name = "BIDDER_ID", nullable = false, updatable = false)
    private User bidder;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public Item getItem() 
        return item;
    

    public void setItem(Item item) 
        this.item = item;
    

    public User getBidder() 
        return bidder;
    

    public void setBidder(User bidder) 
        this.bidder = bidder;
    

    @Override
    public String toString() 
        return "Bid" +
                "id=" + id +
                ", bidder=" + bidder +
                '';
    

private static void itemSeller(EntityManager em) 

    Item item = em.find(Item.class, 1L);
    System.out.println("hello");


编辑:我在声明 System.out.println("hello") 处设置了断点。我检查了项目对象。看图片:

【问题讨论】:

你如何确定它是热切加载的?你的测试是什么? 1-N 的默认值为 LAZY,因此指定它是没有意义的。提供者所做的是特定于您的 JPA 提供者(没有“声称”它只是一个提示......在 JPA 规范中)。我使用的提供者 (DataNucleus) 始终尊重我告诉它使用的内容。你的可能认为它比你更了解?它比你更了解吗? @NeilStockton Hibernate 当然支持延迟加载。是的,JPA 规范确实这么说:docs.oracle.com/javaee/7/api/javax/persistence/…. 通过检查调试器中的对象,您要求它调用列表的方法以显示其大小、内容等。这当然会懒惰地初始化列表。您的 toString() 方法也是如此,它会隐式循环遍历列表以打印它。 【参考方案1】:

通过在调试器中检查对象,您要求它调用列表的方法以显示其大小、内容等。当然,这会延迟初始化列表。

toString() 方法也是如此,它会隐式循环遍历列表以打印它。

【讨论】:

看到你的回答后,我觉得我的问题很愚蠢。我考虑过删除这篇文章,因为我太丢脸了。现在我对投票的数量感到惊讶,我很高兴即使是我的愚蠢问题也能对其他人派上用场。再次感谢您的回答。 @inherithandle 没有必要为只有在我们尝试时才会学习而感到羞耻,我在谷歌上输入了同样的担忧并登陆您的线程,看看一个问题如何帮助其他人。感谢询问【参考方案2】:

作为 Hibernate 文档 @OneToMany--默认 fetchType 是 LAZY @ManyToOne--默认 fetchType 是 EAGER。

如果你想改变那么 fetch=fetchType.LAZY/EAGER

基本上,休眠对象有两次1)实体对象2)值对象。所以在你的情况下,项目与投标有一对多的关系,如果你当时检索项目类,休眠将不会获取相关的投标类记录,因为您确实获取类型是 LAZY,但是您获取 Bid Class 记录休眠为您急切获取相关项目,因为 Bid 与 Item 类具有 ManyToOne 关系,并且 ManyToOne 的默认获取类型是 EAGER。

【讨论】:

以上是关于Hibernate:为啥 FetchType.LAZY 注释的集合属性急切地加载?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Spring 在使用 Hibernate 3 时推迟关闭 Hibernate 会话

为啥 hibernate 严格要求定义 hibernate.dialect 属性,而 JPA 规范没有强制要求?

为啥 Hibernate 不支持分布式事务? [关闭]

为啥 Hibernate 会为此 HQL 抛出 QuerySyntaxException?

Hibernate - 为啥延迟加载 String 属性? [复制]

为啥需要传统的 Hibernate?