【问题标题】:Hibernate: one-to-one lazy loading, optional = falseHibernate:一对一延迟加载,可选 = false
【发布时间】:2013-08-01 23:56:02
【问题描述】:

我遇到了一对一延迟加载在休眠中不起作用的问题。我已经已经解决了,但仍然正确理解会发生什么。

我的代码(延迟加载在这里不起作用,当我拉人时 - 地址也被提取):

@Entity
public class Person{

  @Id
  @SequenceGenerator(name = "person_sequence", sequenceName = "sq_person")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence")
  @Column(name = "id")
  private long personID;

  @OneToOne(mappedBy="person", cascade=CascadeType.ALL, fetch = FetchType.LAZY)
  private Adress address;
  //.. getters, setters
}

@Entity
public class Address {

  @Id
  @Column(name="id", unique=true, nullable=false)
  @GeneratedValue(generator="gen")
  @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
  private long personID;

  @PrimaryKeyJoinColumn
  @OneToOne
  private FileInfo person;
}

但是:如果我在 OneToOne 关系中添加 optional=false,延迟加载工作正常

@OneToOne(mappedBy="person", cascade=CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private Adress address;

问题/恳求:请解释一下optional=false注解如何帮助实现延迟加载。

PS我看过post1post2的帖子,明白为什么简单的OneToOne不能偷懒,但我仍然无法掌握optional=false的魔法。

【问题讨论】:

  • 嘿@Volodymyr,我和你有同样的问题。我正在尝试将 BLOB 列与实体分开。父实体有子实体。子实体包含二进制列。父母和孩子是same table,所以我使用@OneToOne 关系。虽然我使用了 LAZY fetchType 但它似乎不起作用。当我输入optional=false 时,它起作用了。任何解释都将不胜感激。
  • @Emerald214 抱歉,那是 2 年前的事了。目前我正在写 JS Mobile,帮不了你
  • OneToOne optional = false 不适用于 CascadeType.PERSIST,请参阅:hibernate.atlassian.net/browse/HHH-9670

标签: hibernate jpa lazy-loading one-to-one


【解决方案1】:

如果关联是可选的,Hibernate 无法在不发出查询的情况下知道给定人员的地址是否存在。因此它无法使用代理填充地址字段,因为可能没有引用此人的地址,也无法使用null 填充它,因为可能存在引用此人的地址。

当您将关联设为强制性(即optional=false)时,它会信任您并假定地址存在,因为关联是强制性的。所以它直接用代理填充地址字段,知道有一个地址引用这个人。

【讨论】:

  • 如果您尝试在没有地址的情况下保存 Personne,optional=false 不起作用:“org.hibernate.PropertyValueException: not-null property references a null or transient value:”
  • optional = false 表示...地址不是可选的。所以这是强制性的。因此将其设置为 null 会引发异常。这是意料之中的事。
  • 有可能,只是它实际上不会延迟加载关联。也可以通过使用 LazyToOne(NO_PROXY) 并在构建时检测字节码,IIRC,但我有过不好的经历。如果关联是可选的,您最好使用专用的连接列。
  • 是的,我已经测试了 LazyToOne(NO_PROXY) 并在构建时检测字节码,但是像你一样有不好的经验(使用另一个 lib HibernateJackson)。我终于决定不映射关联并在不同的 DAO 中单独管理表。
  • optional = false,对我不起作用,它仍然急切地获取那些实体。 @OneToOne(fetch = FetchType.LAZY, mappedBy = "fundSeries", optional = false) private FundSeriesDetailEntity fundSeriesDetail;
【解决方案2】:

最简单的一种是伪造一对多关系。这将起作用,因为集合的延迟加载比单个可为空属性的延迟加载要容易得多,但如果您使用复杂的 JPQL/HQL 查询,通常这种解决方案非常不方便。

另一种是使用构建时字节码检测。有关更多详细信息,请阅读 Hibernate 文档:19.1.7。使用惰性属性获取。请记住,在这种情况下,您必须将 @LazyToOne(LazyToOneOption.NO_PROXY) 注释添加到一对一关系以使其变得惰性。将 fetch 设置为 LAZY 是不够的。

最后一个解决方案是使用运行时字节码检测,但它仅适用于在成熟的 JEE 环境中使用 Hibernate 作为 JPA 提供程序的人(在这种情况下,将“hibernate.ejb.use_class_enhancer”设置为 true 应该可以解决问题:Entity Manager配置)或使用配置了 Spring 的 Hibernate 来进行运行时编织(这在某些较旧的应用程序服务器上可能难以实现)。在这种情况下,@LazyToOne(LazyToOneOption.NO_PROXY) 注释也是必需的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 2011-07-25
    • 2018-11-22
    • 1970-01-01
    相关资源
    最近更新 更多