在我们正在开发的此应用程序中,我们注意到一个 View 特别慢。我剖析了该 View ,发现即使数据库中只有两个对象要获取,hibernate仍然执行了一个查询,该查询花费了10秒。所有OneToManyManyToMany关系都是惰性的,因此这不是问题。在检查实际执行的SQL时,我注意到查询中有80多个联接。

在进一步检查该问题时,我注意到该问题是由实体类之间的OneToOneManyToOne关系的深层次结构引起的。因此,我想,我只是让它们变得懒惰,应该可以解决问题。但是注释@OneToOne(fetch=FetchType.LAZY)@ManyToOne(fetch=FetchType.LAZY)似乎不起作用。要么我得到一个异常(exception),要么然后它们实际上没有被代理对象替换,因此变得懒惰。

任何想法,我将如何使它工作?请注意,我不使用persistence.xml定义关系或配置详细信息,所有操作均在Java代码中完成。

最佳答案

首先,对 KLE 的答案进行一些说明:

  • 不受约束(可为空)的一对一关联是没有字节码检测就无法代理的唯一关联。原因是所有者实体必须知道关联属性应包含代理对象还是NULL,并且由于通常是通过共享PK进行一对一映射,因此无法通过查看其基表的列来确定该属性。无论如何,必须急切地使代理变得毫无意义。这是more detailed的解释。
  • 多对一关联(显然是一对多)不受此问题的困扰。所有者实体可以轻松地检查其自己的FK(如果是一对多,则最初会创建空集合代理并按需填充),因此关联可以很懒。
  • 用一对多替换一对一几乎不是一个好主意。您可以用唯一的多对一替换它,但是还有其他(可能更好)的选择。

  • Rob H. 有一个有效的观点,但是您可能无法实现它,具体取决于您的模型(例如,如果一对一关联是可为空的)。

    现在,就原始问题而言:

    A)@ManyToOne(fetch=FetchType.LAZY)应该可以正常工作。您确定查询本身不会覆盖它吗?可以在HQL中指定join fetch和/或通过Criteria API显式设置获取模式,这将优先于类注释。如果不是这种情况,但您仍然遇到问题,请发布您的类(class),查询和生成的SQL,以进行更多的即时对话。

    B)@OneToOne比较棘手。如果绝对不能为空,请遵循Rob H.的建议,并这样指定:
    @OneToOne(optional = false, fetch = FetchType.LAZY)
    

    否则,如果您可以更改数据库(向所有者表添加外键列),请进行更改并将其映射为“joined”:
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="other_entity_fk")
    public OtherEntity getOther()
    

    并在OtherEntity中:
    @OneToOne(mappedBy = "other")
    public OwnerEntity getOwner()
    

    如果您不能做到这一点(并且不能随心所欲地抓取),则字节码检测是您唯一的选择。我必须同意 CPerkins ,但是-如果您有 80!由于渴望OneToOne协会而加入,因此遇到了更大的问题:-)

    10-05 22:10