我在合理的时间和合理的查询数量下从数据库中完全加载非常复杂的对象时遇到了问题。
我的对象有很多嵌入的实体,每个实体都有对另一个实体的引用,另一个实体引用另一个实体等等(所以,嵌套级别是 6)
因此,我创建了示例来演示我想要什么: https://github.com/gladorange/hibernate-lazy-loading
我有用户。
用户有 @OneToMany 最喜欢的 Oranges、Apples、Grapevines 和 Peaches 集合。每个 Grapevine 都有 @OneToMany 葡萄集合。每个水果都是只有一个 String 字段的另一个实体。
我正在创建用户,每种水果有 30 种最喜欢的水果,每棵葡萄树有 10 颗葡萄。因此,我在数据库中总共有 421 个实体 - 30*4 个水果、100*30 个葡萄和一个用户。
我想要的是:我想使用不超过 6 个 SQL 查询来加载它们。 并且每个查询不应产生大结果集(对于该示例,大是包含超过 200 条记录的结果集)。
我理想的解决方案如下:
6 个请求。第一次请求返回用户信息,结果集大小为1。
第二个请求返回该用户苹果的信息,结果集大小为30。
第三次、第四次和第五次请求返回与第二次相同的请求(结果集大小 = 30),但针对葡萄藤、橙子和桃子。
第六个请求返回所有葡萄藤的葡萄
这在 SQL 世界中非常简单,但我无法使用 JPA (Hibernate) 实现。
我尝试了以下方法:
使用 fetch join,比如 from User u join fetch u.oranges ...。这太糟糕了。结果集为30*30*30*30,执行时间为10秒。请求数 = 3。我在没有葡萄的情况下尝试过,如果有葡萄,您将获得 x10 大小的结果集。
只需使用延迟加载。这是本例中的最佳结果(@Fetch= SUBSELECT 用于葡萄)。但在那种情况下,我需要手动遍历每个元素集合。另外,subselect fetch 设置太全局了,所以我想要一些可以在查询级别上工作的东西。结果集和时间接近理想。 6 个查询和 43 毫秒。
加载实体图。与 fetch join 相同,但它也会请求每个葡萄获取葡萄藤。然而,结果时间更好(6 秒),但仍然很糟糕。请求数 > 30。
我试图通过在单独的查询中“手动”加载实体来欺骗 JPA。喜欢:
SELECT u FROM User where id=1; SELECT a FROM Apple where a.user_id=1;
这比延迟加载要差一点,因为它需要对每个集合进行两次查询:第一次查询手动加载实体(我完全控制这个查询,包括加载关联的实体),第二次查询延迟加载Hibernate 本身的相同实体(这是由 Hibernate 自动执行的)
执行时间为52次,查询次数=10次(用户1次,葡萄1次,每个水果集合4*2次)
实际上,结合 SUBSELECT 提取的“手动”解决方案允许我使用“简单”提取连接在一个查询中加载必要的实体(如 @OneToOne 实体)所以我将使用它。但我不喜欢我必须执行两个查询来加载集合。
有什么建议吗?
最佳答案
我通常使用 batch fetching 覆盖 99% 的此类用例对于实体和集合。如果您在读取它们的同一个事务/ session 中处理获取的实体,那么您不需要做任何额外的事情,只需导航到处理逻辑所需的关联,生成的查询将是非常理想的。如果你想返回分离的实体,那么你手动初始化关联:
User user = entityManager.find(User.class, userId);
Hibernate.initialize(user.getOranges());
Hibernate.initialize(user.getApples());
Hibernate.initialize(user.getGrapevines());
Hibernate.initialize(user.getPeaches());
user.getGrapevines().forEach(grapevine -> Hibernate.initialize(grapevine.getGrapes()));
请注意,最后一个命令不会实际对每个葡萄树执行查询,因为多个葡萄集合(最多指定的@BatchSize ) 在您初始化第一个时被初始化。您只需迭代所有这些以确保所有都已初始化。
这种技术类似于您的手动方法,但效率更高(不会为每个集合重复查询),并且在我看来更具可读性和可维护性(您只需调用 Hibernate.initialize 而不是手动编写Hibernate 自动生成的相同查询)。
关于java - Hibernate:复杂对象的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47574252/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc