当前位置: 首页 > 面试题库 >

休眠:复杂对象的初始化

田兴怀
2023-03-14
问题内容

在合理的时间内从数据库中完全加载非常复杂的对象以及合理的查询数量时,我遇到了问题。

我的对象有很多嵌入式实体,每个实体都引用了另一个实体,另一个实体又引用了另一个,依此类推(因此,嵌套级别为6)

因此,我创建了示例来演示我想要的内容:https : //github.com/gladorange/hibernate-lazy-
loading

我有用户。

用户有@OneToMany喜欢的 橙子,苹果,葡萄干和桃子的
集合。每个葡萄藤都有@OneToMany葡萄的集合。每个水果都是只有一个String字段的另一个实体。

我正在为用户创建每种类型的30种最喜欢的水果,每个葡萄藤有10个葡萄。因此,在数据库中总共有421个实体-30 * 4水果,100 * 30葡萄和一个用户

我想要的是:我想使用不超过6个SQL查询来加载它们。而且每个查询都不应产生较大的结果集(对于该示例,big是一个具有200条以上记录的结果集)。

我理想的解决方案是:

  • 6个要求。第一个请求返回有关用户的信息,结果集的大小为1。

  • 该用户的第二个请求返回有关Apple的信息,结果集的大小为30。

  • 第三,第四和第五个请求返回相同的结果,第二个(结果集大小为30),但对于葡萄,橙子和桃子。

  • 第六个请求为所有葡萄返回葡萄

这在SQL世界中非常简单,但是我无法使用JPA(hibernate)来实现。

我尝试了以下方法:

  1. 使用获取联接,例如from User u join fetch u.oranges ...。太厉害了 结果集为30 * 30 * 30 * 30,执行时间为10秒。请求数=3。我在没有葡萄的情况下进行了尝试,有了葡萄,您将获得x10大小的结果集。

  2. 只需使用延迟加载即可。在此示例中,这是最好的结果(对于葡萄,使用@ Fetch = SUBSELECT)。但是在那种情况下,我需要手动遍历每个元素集合。另外,subselect fetch也是全局设置,因此我希望有一些可以在查询级别使用的东西。结果集和时间接近理想。6个查询和43毫秒。

  3. 使用实体图加载。与获取联接相同,但是它也要求每个葡萄都获得它。但是,结果时间更好(6秒),但仍然很糟糕。请求数> 30。

  4. 我试图通过在单独的查询中“手动”加载实体来欺骗JPA。喜欢:

    在id = 1的用户中选择u;
    

    从a.user_id = 1;的Apple中选择一个;

这比延迟加载要差一些,因为每个集合都需要两个查询:第一个查询到手动加载实体(我对这个查询有完全控制权,包括加载关联的实体),第二个查询来延迟加载相同的实体由Hibernate本身(由Hibernate自动执行)

执行时间为52,查询数量= 10(用户1,葡萄1,每个水果收集4 * 2)

实际上,“手动”解决方案与SUBSELECT fetch结合使用使我可以使用“简单”
fetch联接在一个查询中加载必要的实体(例如@OneToOne实体),因此我将使用它。但是我不喜欢我必须执行两个查询才能加载集合。

有什么建议么?


问题答案:

我将建议如何懒惰地获取葡萄中葡萄的另一种选择:

@OneToMany
@BatchSize(size = 30)
private List<Grape> grapes = new ArrayList<>();

与其进行子选择in (?, ?, etc),不如使用一次子选择来立即获取许多的集合Grape。取而代之的是,?葡萄藤ID将被传递。这与一次查询1个List<Grape>集合相反。

那只是您的武器库的另一种技术。



 类似资料:
  • 问题内容: 我在用Java工作。 我通常会这样设置一些对象: 问题是:在此示例中是否等于,按原样我可以假定对未初始化的对象进行空检查将是准确的? 问题答案: 正确,未显式初始化的引用类型的静态成员和实例成员都由Java 设置为。相同的规则适用于数组成员。 根据Java语言规范的第4.12.5节: 变量的初始值 程序中的每个变量在使用值之前都必须具有一个值: 每个类变量,实例变量或数组组件在创建时均

  • 问题内容: 有没有一种方法可以在不初始化的情况下计算关联集合的大小? 例如 (由于我的where子句更加复杂,而from子句是多态查询,所以我不能以任何其他方式执行此操作是有充分的理由的) 谢谢。 问题答案: 除查询外,可能的解决方案可能是使用(使用XML表示法)映射。这样,您可以使用所需的任何查询来获取Parent,然后在不加载整个集合的情况下进行调用(仅执行类型查询)。 有了注释,它将是 更新

  • 前面一节的 Fruit 类有两个实变量,分别表述水果的类型和状态.直到为这个类写了一个定制的inspect方法,我们方才了解它不会对一个缺乏属性的水果做出合理的解释.幸运的是,Ruby提供了一种允许实变量总是被初始化的方法. initalize方法 当Ruby创建一个新对象时,它总是会寻找一个名为 initialize 的方法并执行它.因此,我们可以简单通过一个initialize方法向实变量中加

  • 问题内容: 据我了解(如果我错了,请纠正我),Hibernate使用对象引用来检查对象的相等性。当Hibernate识别同一数据库记录中有多个对象附加时,它将引发以下异常。 我的问题是,Hibernate是否使用方法检查对象是否相等(默认的equal方法使用对象引用)?如果为true,则重写的方法会改变Hibernate的行为吗? 注意:我的问题不是关于Hibernate持久对象中的实现或方法问题

  • 问题内容: 对数据库有以下查询: 在获取employee.address.street,employee.address.houseNumber或employee.address.city时,它将失败,但以下情况除外: 员工映射: 地址映射: 对于其他类(办公室,公司等),这​​是绝对正常的。如果注释,则在jsp应用程序中加载地址字段的行将正常工作。怎么了?顺便说一下,尽管有异常,它仍显示有关js

  • 问题内容: 如何取消代理hibernate对象,以支持多态? 考虑以下示例。A和B类是两个hibernate实体。B具有两个子类型C和D。 该代码无法执行C或D块,因为B集合已被延迟加载,并且B的所有实例均为Hibernate代理。我想要一种取消代理的方法。 注意:我意识到可以优化查询以急切地获取所有B。我正在寻找替代方案。 问题答案: 这是我们的解决方案,已添加到持久性工具中: