Hibernate (JPA) 如何进行急切查询,加载所有子对象
关于我的之前的问题,我想确保所有子对象被加载,因为我有多个线程可能需要访问数据(从而避免延迟加载异常)。 我知道执行此操作的方法是在查询(EJB QL)中使用“fetch”关键字。 像这样:
select distinct o from Order o left join fetch o.orderLines
假设一个带有 Order
类的模型,其中包含一组 OrderLines
。
我的问题是,似乎需要“distinct”关键字,否则我似乎会为每个 OrderLine
返回一个 Order
。 我做的事正确吗?
也许更重要的是,有没有办法拉入所有子对象,无论多深? 我们有大约 10-15 个类,对于服务器,我们需要加载所有内容...我避免使用 FetchType.EAGER
因为这意味着它总是渴望,特别是 Web 前端加载所有内容 - 但是也许这就是要走的路——你就是这么做的吗? 我似乎记得我们之前尝试过这个,然后网页速度非常慢 - 但这也许意味着我们应该使用二级缓存?
Relating to my earlier question, I want to ensure all the child objects are loaded as I have a multiple threads that may need to access the data (and thus avoid lazy loading exceptions). I understand the way to do this is to use the "fetch" keyword in the query (EJB QL). Like this:
select distinct o from Order o left join fetch o.orderLines
Assuming a model with an Order
class which has a set of OrderLines
in it.
My question is that the "distinct" keyword seems to be needed as otherwise I seem to get back an Order
for each OrderLine
. Am I doing the right thing?
Perhaps more importantly, is there a way to pull in all child objects, no matter how deep? We have around 10-15 classes and for the server we will need everything loaded... I was avoiding using FetchType.EAGER
as that meant its always eager and in particular the web front end loads everything - but perhaps that is the way to go - is that what you do? I seem to remember us trying this before and then getting really slow webpages - but perhaps that means we should be using a second-level cache?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您是否尝试过使用结果转换器? 如果您使用 Criteria 查询,则可以应用结果转换器(尽管 分页和结果存在一些问题Transformer):
em.getDelegate()
是一个只有在使用 hibernate 时才有效的 hack。如果您仍然感兴趣,我在此线程中回答了类似的问题如何序列化休眠集合。
基本上,您使用一个名为 dozer 的实用程序,将 bean 映射到另一个 bean,通过执行此操作,您将触发所有延迟加载。 正如您可以想象的那样,如果急切地获取所有集合,效果会更好。
Have you tried using a result transformer? If you use Criteria queries, you can apply a result transformer (although there are some problems with pagination and result transformer):
the
em.getDelegate()
is a hack that only works if you are using hibernate.If you are still interested, I responded a similar question in this thread how to serialize hibernate collections.
Basically you use a utility called dozer that maps beans onto another beans, and by doing this you trigger all your lazy loads. As you can imagine, this works better if all collections are eagerly fetched.
在我看来,更改注释是一个坏主意。 因为它不能在运行时更改为惰性。 最好让一切变得懒惰,并根据需要获取。
如果没有映射,我不确定我是否理解您的问题。 对于您描述的用例,左连接获取应该是您所需要的。 当然,如果订单行有一个订单作为其父级,您将获得每个订单行的订单。
Changing the annotation is a bad idea IMO. As it can't be changed to lazy at runtime. Better to make everything lazy, and fetch as needed.
I'm not sure I understand your problem without mappings. Left join fetch should be all you need for the use case you describe. Of course you'll get back an order for every orderline if orderline has an order as its parent.
我不确定是否在 EJBQL 中使用 fetch 关键字,您可能会将其与注释混淆...
您是否尝试过将 FetchType 属性添加到关系属性中?
@OneToMany(fetch=FetchType.EAGER)?
请参阅:
http://java.sun.com/javaee /5/docs/api/javax/persistence/FetchType.html
http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple
I'm not sure about using the fetch keyword in your EJBQL, you might be getting it confused with the annotation...
Have you tried adding the FetchType property to your relationship attribute?
@OneToMany(fetch=FetchType.EAGER)?
See:
http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html
http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple
这仅适用于 ManyToOne 关系,并且 @ManyToOne(fetch=FetchType.EAGER) 可能适合它们。
不鼓励急切地获取多个 OneToMany 关系和/或不起作用,正如您可以在 Jeremy 发布的链接中阅读的那样。 想想执行这样的获取操作所需的 SQL 语句...
That would only work for ManyToOne relations and for them @ManyToOne(fetch=FetchType.EAGER) would probably appropriate.
Fetching more than one OneToMany relation eagerly is discouraged and/or does not work as you can read in the link Jeremy posted. Just think about the SQL statement that would be needed to do such a fetch...
您也许可以使用(独立的)条件查询并设置获取模式来执行类似的操作。 例如,
You might be able to do something like that using a (detached) criteria query, and setting the fetch mode. E.g.,
我所做的是重构代码以保留对象到实体管理器的映射,并且每次需要刷新时,关闭对象的旧实体管理器并打开一个新实体管理器。 我在没有 fetch 的情况下使用了上面的查询,因为这对于我的需求来说太深了 - 只需执行简单的连接即可拉入 OrderLines - fetch 使其变得更加深入。
我只需要几个对象,大约 20 个,所以我认为拥有 20 个开放实体管理器的资源开销不是问题 - 尽管 DBA 在启用时可能有不同的看法...
我也重新-工作,以便数据库工作在主线程上并具有实体管理器。
克里斯
What I have done is to refactor the code to keep a map of objects to entity managers and each time I need to refresh, close the old entitymanager for the object and open a new one. I used the above query without the fetch as that is going too deep for my needs - just doing a plain join pulls in the OrderLines - the fetch makes it go even deeper.
There are only a few objects that I need this for, around 20, so I think the resource overhead in having 20 open entitymanagers is not an issue - although the DBAs may have a different view when this goes live...
I also re-worked things so that the db work is on the main thread and has the entity manager.
Chris
如果问题只是 LazyInitializationExceptions,您可以通过添加 OpenSessionInViewFilter 来避免这种情况。
这将允许在视图中加载对象,但无助于解决速度问题。
If the problem is just LazyInitializationExceptions, you can avoid that by adding an OpenSessionInViewFilter.
This will allow the objects to be loaded in the view, but will not help with the speed issue.