带有Spring代理的LazyCollectionOption.EXTRA?

时间:2014-05-21 14:26:11

标签: java spring hibernate jpa hibernate-mapping

我想显示一个包含数据库所有用户的表。该表还应包含用户对象中包含的列表的元素数。 由于我只需要大小/数量,我想阻止获取整个列表。因此,我正在使用LazyCollectionOption.EXTRA,文档说明:

  

EXTRA = .size()和.contains()不会初始化整个集合

但以下情况仍不奏效:

@Entity
class User {
    @OneToMany
    @LazyCollection(LazyCollectionOption.EXTRA)
    List<Transaction> transactions;
}

当我致电user.getTransactions().size()时,结果是:

  

引起:org.hibernate.LazyInitializationException:懒得失败   初始化角色集合:User.transactions,但不能   初始化代理 - 没有会话   org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)     在   org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)     在   org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155)     在   org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:278)

2 个答案:

答案 0 :(得分:3)

我不认为它是:

@LazyCollection(LazyCollectionOption.EXTRA)

这会给你带来麻烦。

我认为您正在获取Hibernate会话中的“用户”列表,该列表会在您想要访问用户的事务之前关闭。

这是LazyInitializationException的典型场景,因为当会话仍然打开时,嵌套集合尚未初始化。

获取所有用户及其所有交易将获得笛卡尔积,从而导致性能问题。

我认为获取用户列表并使用子选择提取来检索交易是正常的:

@OneToMany
@Fetch(FetchMode.SUBSELECT)
List<Transaction> transactions;

这将再发出一个select来在您需要时获取所有未初始化的事务。这将要求您至少访问一个当前附加的用户事务,以触发所有未初始化的当前附加事务的额外提取。

否则您可以使用批量提取:

@OneToMany
@BatchSize(size = 50)
List<Transaction> transactions;

同样,这需要一个打开的Session,并且在请求某个User.transactions时,所有用户关联的事务将以50个批次进行初始化。

但由于@BatchSize仅为集合设置,而不是@Entity级别,这意味着在最好的情况下,您仍然需要N个额外查询N当前连接的用户。如果每个用户有超过50个交易,您将需要超过N个查询。这可能比子选择提取更糟糕,只需要一个查询(the original query is rerun using a sub-select to fetch all query related Users' transactions)。

答案 1 :(得分:2)

我解释它的方式是 - 不,它不会初始化整个集合,但它会进行一些初始化。

阅读Hibernate文档,states

  

&#34;特懒惰&#34;集合获取:根据需要从数据库中访问集合的各个元素。除非绝对需要,否则Hibernate会尝试不将整个集合提取到内存中。它适用于大型系列。

文档在某些地方令人困惑,但可以解释为对.size()的调用将触发对数据库的调用,但不会初始化整个集合,而只会初始化必要的值以返回该方法的结果。