hibernate懒惰的错误,但我不想要那些数据

时间:2014-07-16 11:59:34

标签: java hibernate lazy-initialization

我有两个字符串/数字/的POJO ...我想只得到这个pojo,而没有任何可以通过hibernate附加的列表/地图/集中的子POJO。如果我执行查询以获得第一个pojo,当有人触摸那些子对象时抛出异常。

这是正常行为,我同意这一点,但有没有办法,不要称之为:

object.setSomeMap(null);

但要将其设置为默认行为?我不认为将这样的每个属性设置为最佳解决方案,因为我拥有相当大的模型。

谢谢!

1 个答案:

答案 0 :(得分:1)

FetchType设置为FetchType.LAZY,从数据库加载类时不会加载它们。我给你举个例子:

@Entity
@Table(name="FOO")
public class Foo{

    @Id
    @GeneratedValue
    @Column
    private int id;

    @Column
    private String prop1;

    @Column
    private String prop2;

    //You don't have to set fetch type like this, as lazy is the default for collections,
    //but it doesn't really hurt anything
    @OneToMany(fetch=FetchType.LAZY)
    private List<Bar> listOfBars;
}

因此,当您加载Foo课程时,idprop1prop2将从数据库加载并设置,但listOfBars个对象不会填充。

每当您尝试访问listOfBars对象时,Hibernate会检测到它并尝试填充对象,然后才能获取它。 AFAIK如果您尝试将listOfBars设置为null,Hibernate将检测到此并尝试删除您的外键,如果更新对象,则有效删除listOfBars的所有成员。例如:

@Transactional
public Foo doStuffWithFoo(int id){
    Foo foo = fooDao.find(id);
    //Set listOfBars to null so we can't call it.
    //This is bad and will cause disaster when we update Foo.
    foo.setListOfBars(null);

    //Do some stuff with Foo that changes values.

    fooDao.saveOrUpdate(foo);
    return foo;
}

因为您在这里将listOfBars对象设置为null,AFAIK Hibernate将删除所有外键,因为您的列表不再存在。 Hibernate知道列表是空的,因为它在创建对象时没有填充它,而是一个你设置为null / empty的列表。如果是前者的情况,它除了可能在需要时级联更新状态之外什么都不做。对于后者,如果orphanRemoval设置为true,它将清除您的关联,可能删除Bar对象。

但是,如果您从方法中返回listOfBars后尝试访问Foo,则会出现其他问题。出现此问题的原因是,在您尝试访问@Transactional之前,您最初用于提取Foo课程的listOfBars会话已结束。此时您有3个选项,每个选项都有自己的问题。

第一个选项(这是大多数人尝试的,因为它不起作用而感到沮丧)是您可以打开一个新会话,并尝试填充您的listOfBars对象。 Hibernate假定您的Foo对象和Bar中的所有listOfBars对象都可能在事务结束后发生了变化(这是完全正确的),因此它会引发异常。

另一种选择是再次获取整个Foo对象 并填充新事务中的listOfBars对象。这样做的问题是,做这样的多次选择是非常低效的。

您最后的选择是永远不要尝试访问listOfBars对象,如果您知道它不在那里。您甚至无法执行空检查,因为Hibernate将检测您对getListOfBars()的调用,并尝试在实际进行空检查之前填充该对象。

我编写了一个Hibernate教程,用于创建对象关系here,您可能会发现它们很有帮助。我还讨论了诸如Lazy vs Eager对象集合以及其他一些Hibernate的东西,它们在设计用于Hibernate的类时会有所帮助。

祝你好运