JPA中的简单byte[]字段级别的lazy加载

10

很遗憾,下面的代码不起作用。图像总是被检索!

@Entity
public Car implements Serializable {
    ...
    @Basic(fetch = FetchType.LAZY) //Neither with @Lob
    private byte[] image;
    ...
}

设置:JPA 2.0 / Hibernate 3.5 / MySQL 5.5

4个回答

3
这个技巧的方法在这个主题中描述:http://justonjava.blogspot.it/2010/09/lazy-one-to-one-and-one-to-many.html 我已经在Hibernate v.4.3.5和JPA v.1.5.0,PostgreSQL 9.3上测试过,运行良好。示例:
public class Attachment implements FieldHandled{
    @Transient
    private FieldHandler fieldHandler;
...
...
    @Lob
    @Column(name=CONTENT, nullable=false)
    @Basic(fetch = FetchType.LAZY, optional = false)
    private byte[] content;

...
...
    public byte[] getContent() {
    if(fieldHandler!=null){
        return (byte[])fieldHandler.readObject(this, "content", content);
    }
    return content;
    }

    public void setContent(byte[] content) {
    if(fieldHandler!=null){
        fieldHandler.writeObject(this, "content", this.content, content);
        return;
    }
    this.content = content;
    }

}

注意:如果你正在使用CGLib,请实现net.sf.cglib.transform.impl.InterceptFieldEnabled而不是FieldHandled,使用相同的方法。

3
请记住,当您指定时,JPA提供程序不需要惰性获取数据。这是一个提示而不是要求。
JPA规范2.0 11.1.6
EAGER策略是对持久化提供程序运行时的要求,必须急切地获取数据。LAZY策略是对持久化提供程序运行时的提示,应该在首次访问数据时懒惰地获取数据。实现允许急切地获取指定了LAZY策略提示的数据。特别地,对于使用基于属性的访问的基本映射,可能仅可用于延迟获取。

谢谢你,Pedro!那么我迷路了吗? - CelinHC
Pedro,我真的认为这是一个Hibernate的bug(这不会是他们在JPA实现上做的第一个)。看看这个问题:https://dev59.com/6HE85IYBdhLWcg3wzWzM。那个人基本上和你有同样的问题,建议解决方案:在你的实体(不包括图像)和另一个只包含byte[]的实体之间进行一对一映射,并使该关联懒加载。 - Shivan Dragon
当然,这可能是一个Hibernate的bug,但是你不能假设JPA提供程序会懒加载你的数据。在我看来,如果你的逻辑依赖于这样的特性,那么它应该被很好地记录下来,因为当更改JPA提供程序时,你可能会感到惊讶。 - Piotr Nowicki
同意,但我认为这里发生的情况更多是“休眠不进行懒加载因为有缺陷”,而不是“休眠不进行懒加载因为高度尊重JPA规范,该规范仅仅是一个提示”。我认为如果您尝试通过关联进行懒加载,Hibernate实际上会进入“按照JPA规范进行懒加载”并选择实际进行懒加载。 - Shivan Dragon
好的,CellinHc,你能试试@AndreiBodnarescu建议的方法吗?另外,你可以检查一下从基于字段的访问转换为基于属性的访问是否会改变什么。 - Piotr Nowicki
我为图像创建了一个包装器映射类,并使用@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)进行了映射... 一切都运行良好... 它还不够完美,但是... - CelinHC

0
据我所知,只有在存在@OneToMany关系时(除非使用类编织),才可能进行惰性加载。至少这是EclipseLink的解释http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Basic_Mappings/Lazy_Basics,从Java语言的角度来看是有道理的。 当您拥有...
@OneToMany (fetch = FetchType.LAZY)
Collection<Employee> employees;

Collection是一个接口,因此JPA可以轻松地使用自己的集合实现,在您开始迭代时懒加载数据。如果您有一个带有byte[]类型字段的对象,它的值要么为null,要么包含所有数据,这就是Java的工作方式。唯一绕过这个问题的方法是使用类编织并创建字节码,看起来像一个字节数组,但在访问它之前不包含任何数据。


看起来 OP 正在使用 Hibernate 而不是 EclipseLink。 - Mickaël B.

0

我记得这是一个问题,大约在2007年左右:即为什么字节数组即使被声明为lazy,也会被急切地获取。显然,Hibernate的开发人员仍然没有解决这个问题。

以下是一些可行的替代方案:

首先,尝试使用@Lob注释您的字段,看看是否按预期工作。

其次,将byte[]替换为java.sql.Blob,它具有设置和获取实际字节数组的便捷方法,因此不会进行大规模重构,并且这应该可以解决懒加载问题:

http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Blob.html


谢谢Andrei,但是这些方法对我不起作用。有很大的问题!@Lob @Basic(fetch = FetchType.LAZY) Blob private byte[] image; EntityManager无法持久化此属性...持久化所有字段,而image保持为空。我正在使用具体类SerialBlob - CelinHC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接