Java 如何阻止 Hibernate 急切地获取多对一关联对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/222453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to stop Hibernate from eagerly fetching many-to-one associated object
提问by MetroidFan2002
I have a property on a domain object that is declared in a many-to-one element. The basic syntax of this property looks like this:
我在多对一元素中声明的域对象上有一个属性。此属性的基本语法如下所示:
<many-to-one name="propertyName" class="propertyClass" fetch="select" not-found="ignore" lazy="proxy" />
Now, the idea is to have Hibernate NOT eagerly fetch this property. It may be null, so the not-found ignore is set.
现在,我们的想法是让 Hibernate 不要急切地获取这个属性。它可能为空,因此设置了未找到的忽略。
But, Hibernate, upon loading the class containing this association, takes it upon itself to load the actual class (not even a proxy) instance when the parent class is loaded. Since some properties are over 1MB in size, they take up a lot of the heap space.
但是,在加载包含此关联的类时,Hibernate 会在加载父类时自行加载实际类(甚至不是代理)实例。由于一些属性的大小超过 1MB,它们占用了大量的堆空间。
If, however, not-found is set to exception (or defaulted to exception), the parent classes which have this property do load a proxy!
但是,如果 not-found 设置为异常(或默认为异常),则具有此属性的父类会加载代理!
How can I stop hibernate from not loading a proxy, while still allowing this property to be null?
如何阻止休眠不加载代理,同时仍然允许此属性为空?
I found lazy=no-proxy, but the documentation talks about some sort of bytecode modification and doesn't go into any details. Can someone help me out?
我发现lazy=no-proxy,但文档讨论了某种字节码修改,并没有涉及任何细节。有人可以帮我吗?
If it matters, it is the Java version of Hibernate, and it is at least version 3 (I can look up the actual version if it helps, but it is Hibernate 3+ for now).
如果重要的话,它是 Hibernate 的 Java 版本,它至少是版本 3(如果有帮助,我可以查找实际版本,但现在它是 Hibernate 3+)。
I didn't specify earlier, but the Java version is 1.4. So, Java annotations aren't supported.
我之前没有指定,但Java版本是1.4。因此,不支持 Java 注释。
采纳答案by Miguel Ping
If the other end of the association can be null, I believe hibernate must query for the association end in order to determine if it should use a proxy or not (no need for proxy if the other end is null). I can't find the reference to this right now, but I remember reading it somewhere.
如果关联的另一端可以为null,我相信 hibernate 必须查询关联端以确定它是否应该使用代理(如果另一端为null则不需要代理)。我现在找不到对此的引用,但我记得在某处读过它。
In order to provide lazy-loading of fieldsthe documentation refers to bytecode enhancements on fields at buildtime: Using lazy property fetching. Here is an excerpt:
为了提供字段的延迟加载,文档在构建时引用了字段的字节码增强:使用延迟属性获取。这是摘录:
Hibernate3 supports the lazy fetching of individual properties. This optimization technique is also known as fetch groups. Please note that this is mostly a marketing feature, as in practice, optimizing row reads is much more important than optimization of column reads. However, only loading some properties of a class might be useful in extreme cases, when legacy tables have hundreds of columns and the data model can not be improved.
Lazy property loading requires buildtime bytecode instrumentation! If your persistent classes are not enhanced, Hibernate will silently ignore lazy property settings and fall back to immediate fetching.
Hibernate3 支持延迟获取单个属性。这种优化技术也称为获取组。请注意,这主要是一种营销功能,因为在实践中,优化行读取比优化列读取重要得多。然而,当遗留表有数百列并且数据模型无法改进时,仅加载类的某些属性可能在极端情况下有用。
延迟属性加载需要构建时字节码检测!如果您的持久类没有得到增强,Hibernate 将默默地忽略惰性属性设置并回退到立即获取。
回答by leeand00
If you're passing the hibernate object from the model to the view via the controller, don't!
如果您通过控制器将休眠对象从模型传递到视图,请不要!
Instead make a "snapshot object" to store the values from the Hibernate object you want to pass to the view and be displayed.
而是创建一个“快照对象”来存储您想要传递给视图并显示的 Hibernate 对象中的值。
Why?The proxy can still retrieve the values when it is in the controller...but when you pass the proxy/object to the view it no longer can retrieve the values because the transaction has already ended. And this is why I have suggested what I have above.
为什么?当它在控制器中时,代理仍然可以检索值……但是当您将代理/对象传递给视图时,它不再可以检索值,因为事务已经结束。这就是为什么我提出了我上面的建议。
回答by Joey Gibson
When using Hibernate annotations, putting @ManyToOne(fetch = FetchType.LAZY) on the association, accomplishes what you want. Have you tried setting fetch="lazy" to see if that works?
使用 Hibernate 注释时,将 @ManyToOne(fetch = FetchType.LAZY) 放在关联上,即可完成您想要的操作。您是否尝试过设置 fetch="lazy" 以查看是否有效?
回答by rudolfson
@Miguel Ping:
I think the page you are referring to is [http://www.hibernate.org/162.html]. As far as I understand, the additional SELECT is needed in the case of the one-to-one side, where the foreign key isn't present. Setting constrained="true"
tells Hibernate, that the other side is always present and no additional SELECT is needed.
@Miguel Ping:我认为您所指的页面是 [ http://www.hibernate.org/162.html]。据我了解,在不存在外键的一对一情况下,需要额外的 SELECT 。设置constrained="true"
告诉 Hibernate,另一端始终存在,不需要额外的 SELECT。
So for the many-to-one side, where the foreign key resides, it shouldn't be necessary to
execute another SELECT since the value of the FK tells if the other end is present or null
. At least, this is how I understand it.
因此,对于外键所在的多对一侧,不需要执行另一个 SELECT,因为 FK 的值表明另一端是否存在或null
. 至少,我是这样理解的。
So far for the theory. The proxy works for me on the foreign key / many-to-one side. The used mapping for the association is:
到此为止的理论。代理在外键/多对一方面对我有用。用于关联的映射是:
<many-to-one name="haendler" column="VERK_HAENDLOID" lazy="proxy" />
<many-to-one name="haendler" column="VERK_HAENDLOID" lazy="proxy" />
But proxying doesn't work for me on the one-to-one side using a mapping like the one described at the given URL (constrained="true"
). Hmm, think I'll open a question for this. ;-)
但是代理在一对一方面对我不起作用,使用类似于给定 URL ( constrained="true"
) 中描述的映射。嗯,我想我会为此提出一个问题。;-)
回答by Civil Disobedient
I found lazy=no-proxy, but the documentation talks about some sort of bytecode modification and doesn't go into any details. Can someone help me out?
我发现lazy=no-proxy,但文档讨论了某种字节码修改,并没有涉及任何细节。有人可以帮我吗?
I'll assume you're using ANT to build your project.
我假设您正在使用 ANT 来构建您的项目。
<property name="src" value="/your/src/directory"/><!-- path of the source files -->
<property name="libs" value="/your/libs/directory"/><!-- path of your libraries -->
<property name="destination" value="/your/build/directory"/><!-- path of your build directory -->
<fileset id="applibs" dir="${libs}">
<include name="hibernate3.jar" />
<!-- include any other libraries you'll need here -->
</fileset>
<target name="compile">
<javac srcdir="${src}" destdir="${destination}" debug="yes">
<classpath>
<fileset refid="applibs"/>
</classpath>
</javac>
</target>
<target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
<classpath>
<fileset refid="applibs"/>
</classpath>
</taskdef>
<instrument verbose="true">
<fileset dir="${destination}">
<!-- substitute the package where you keep your domain objs -->
<include name="/com/mycompany/domainobjects/*.class"/>
</fileset>
</instrument>
</target>
回答by Ramon Havermans
Make sure your class is not final!
确保你的课程不是最终的!